Skip to content

Commit

Permalink
soroban-rpc: Allow Budget Instruction Leeway to be Configured by Clie…
Browse files Browse the repository at this point in the history
…nts (#1131)

* Allow budget instruction leeway to be configured by clients

* Cargo fmt

* Fix CLI tests

* Update resource fee in simulate transaction test

* Refactor GetPreflight parameters into struct

* Update default instruction leeway to 3 million

* Update workflow file to test against SDK update

* Update SDK NPM version for system tests
  • Loading branch information
stellarsaur authored Dec 15, 2023
1 parent 21f5e95 commit 9ea424d
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
# resolution options, using npm release or a gh ref:
#
# option #1, set the version of stellar-sdk based on a npm release version
SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION: 11.0.1
SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION: 11.1.0
# option #2, set the version of stellar-sdk used as a ref to a gh repo if
# a value is set on SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO, it takes
# precedence over any SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION
Expand Down
4 changes: 3 additions & 1 deletion cmd/soroban-cli/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,9 +693,11 @@ soroban config identity fund {address} --helper-url <url>"#
) -> Result<SimulateTransactionResponse, Error> {
tracing::trace!("Simulating:\n{tx:#?}");
let base64_tx = tx.to_xdr_base64(Limits::none())?;
let mut builder = ObjectParams::new();
builder.insert("transaction", base64_tx)?;
let response: SimulateTransactionResponse = self
.client()?
.request("simulateTransaction", rpc_params![base64_tx])
.request("simulateTransaction", builder)
.await?;
tracing::trace!("Simulation response:\n {response:#?}");
match response.error {
Expand Down
19 changes: 16 additions & 3 deletions cmd/soroban-rpc/internal/methods/simulate_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import (
)

type SimulateTransactionRequest struct {
Transaction string `json:"transaction"`
Transaction string `json:"transaction"`
ResourceConfig *preflight.ResourceConfig `json:"resourceConfig,omitempty"`
}

type SimulateTransactionCost struct {
Expand Down Expand Up @@ -46,7 +47,7 @@ type SimulateTransactionResponse struct {
}

type PreflightGetter interface {
GetPreflight(ctx context.Context, readTx db.LedgerEntryReadTx, bucketListSize uint64, sourceAccount xdr.AccountId, opBody xdr.OperationBody, footprint xdr.LedgerFootprint) (preflight.Preflight, error)
GetPreflight(ctx context.Context, params preflight.PreflightGetterParameters) (preflight.Preflight, error)
}

// NewSimulateTransactionHandler returns a json rpc handler to run preflight simulations
Expand Down Expand Up @@ -113,7 +114,19 @@ func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.Ledge
}
}

result, err := getter.GetPreflight(ctx, readTx, bucketListSize, sourceAccount, op.Body, footprint)
resource_config := preflight.DefaultResourceConfig()
if request.ResourceConfig != nil {
resource_config = *request.ResourceConfig
}
params := preflight.PreflightGetterParameters{
LedgerEntryReadTx: readTx,
BucketListSize: bucketListSize,
SourceAccount: sourceAccount,
OperationBody: op.Body,
Footprint: footprint,
ResourceConfig: resource_config,
}
result, err := getter.GetPreflight(ctx, params)
if err != nil {
return SimulateTransactionResponse{
Error: err.Error(),
Expand Down
17 changes: 9 additions & 8 deletions cmd/soroban-rpc/internal/preflight/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,26 +139,27 @@ func (m *metricsLedgerEntryWrapper) GetLedgerEntries(keys ...xdr.LedgerKey) ([]d
return entries, err
}

func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, readTx db.LedgerEntryReadTx, bucketListSize uint64, sourceAccount xdr.AccountId, opBody xdr.OperationBody, footprint xdr.LedgerFootprint) (Preflight, error) {
func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, params PreflightGetterParameters) (Preflight, error) {
if pwp.isClosed.Load() {
return Preflight{}, errors.New("preflight worker pool is closed")
}
wrappedTx := metricsLedgerEntryWrapper{
LedgerEntryReadTx: readTx,
LedgerEntryReadTx: params.LedgerEntryReadTx,
}
params := PreflightParameters{
preflightParams := PreflightParameters{
Logger: pwp.logger,
SourceAccount: sourceAccount,
OpBody: opBody,
SourceAccount: params.SourceAccount,
OpBody: params.OperationBody,
NetworkPassphrase: pwp.networkPassphrase,
LedgerEntryReadTx: &wrappedTx,
BucketListSize: bucketListSize,
Footprint: footprint,
BucketListSize: params.BucketListSize,
Footprint: params.Footprint,
ResourceConfig: params.ResourceConfig,
EnableDebug: pwp.enableDebug,
}
resultC := make(chan workerResult)
select {
case pwp.requestChan <- workerRequest{ctx, params, resultC}:
case pwp.requestChan <- workerRequest{ctx, preflightParams, resultC}:
result := <-resultC
if wrappedTx.ledgerEntriesFetched > 0 {
status := "ok"
Expand Down
28 changes: 28 additions & 0 deletions cmd/soroban-rpc/internal/preflight/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type snapshotSourceHandle struct {
logger *log.Entry
}

const (
defaultInstructionLeeway uint64 = 3000000
)

// SnapshotSourceGet takes a LedgerKey XDR in base64 string and returns its matching LedgerEntry XDR in base64 string
// It's used by the Rust preflight code to obtain ledger entries.
//
Expand Down Expand Up @@ -71,6 +75,25 @@ func FreeGoXDR(xdr C.xdr_t) {
C.free(unsafe.Pointer(xdr.xdr))
}

type ResourceConfig struct {
InstructionLeeway uint64 `json:"instructionLeeway"`
}

func DefaultResourceConfig() ResourceConfig {
return ResourceConfig{
InstructionLeeway: defaultInstructionLeeway,
}
}

type PreflightGetterParameters struct {
LedgerEntryReadTx db.LedgerEntryReadTx
BucketListSize uint64
SourceAccount xdr.AccountId
OperationBody xdr.OperationBody
Footprint xdr.LedgerFootprint
ResourceConfig ResourceConfig
}

type PreflightParameters struct {
Logger *log.Entry
SourceAccount xdr.AccountId
Expand All @@ -79,6 +102,7 @@ type PreflightParameters struct {
NetworkPassphrase string
LedgerEntryReadTx db.LedgerEntryReadTx
BucketListSize uint64
ResourceConfig ResourceConfig
EnableDebug bool
}

Expand Down Expand Up @@ -216,12 +240,16 @@ func getInvokeHostFunctionPreflight(params PreflightParameters) (Preflight, erro

handle := cgo.NewHandle(snapshotSourceHandle{params.LedgerEntryReadTx, params.Logger})
defer handle.Delete()
resourceConfig := C.resource_config_t{
instruction_leeway: C.uint64_t(params.ResourceConfig.InstructionLeeway),
}
res := C.preflight_invoke_hf_op(
C.uintptr_t(handle),
C.uint64_t(params.BucketListSize),
invokeHostFunctionCXDR,
sourceAccountCXDR,
li,
resourceConfig,
C.bool(params.EnableDebug),
)
FreeGoXDR(invokeHostFunctionCXDR)
Expand Down
5 changes: 5 additions & 0 deletions cmd/soroban-rpc/lib/preflight.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ typedef struct xdr_vector_t {
size_t len;
} xdr_vector_t;

typedef struct resource_config_t {
uint64_t instruction_leeway; // Allow this many extra instructions when budgeting
} resource_config_t;

typedef struct preflight_result_t {
char *error; // Error string in case of error, otherwise null
xdr_vector_t auth; // array of SorobanAuthorizationEntries
Expand All @@ -43,6 +47,7 @@ preflight_result_t *preflight_invoke_hf_op(uintptr_t handle, // Go Handle to for
const xdr_t invoke_hf_op, // InvokeHostFunctionOp XDR
const xdr_t source_account, // AccountId XDR
const ledger_info_t ledger_info,
const resource_config_t resource_config,
bool enable_debug);

preflight_result_t *preflight_footprint_ttl_op(uintptr_t handle, // Go Handle to forward to SnapshotSourceGet
Expand Down
16 changes: 12 additions & 4 deletions cmd/soroban-rpc/lib/preflight/src/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,28 @@ use state_ttl::{get_restored_ledger_sequence, TTLLedgerEntry};
use std::cmp::max;
use std::convert::{TryFrom, TryInto};

use crate::CResourceConfig;

#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_host_function_transaction_data_and_min_fee(
op: &InvokeHostFunctionOp,
pre_storage: &LedgerStorage,
post_storage: &Storage,
budget: &Budget,
resource_config: CResourceConfig,
events: &[DiagnosticEvent],
invocation_result: &ScVal,
bucket_list_size: u64,
current_ledger_seq: u32,
) -> Result<(SorobanTransactionData, i64)> {
let ledger_changes = get_ledger_changes(budget, post_storage, pre_storage, TtlEntryMap::new())?;
let soroban_resources =
calculate_host_function_soroban_resources(&ledger_changes, &post_storage.footprint, budget)
.context("cannot compute host function resources")?;
let soroban_resources = calculate_host_function_soroban_resources(
&ledger_changes,
&post_storage.footprint,
budget,
resource_config,
)
.context("cannot compute host function resources")?;

let contract_events_size =
calculate_contract_events_size_bytes(events).context("cannot calculate events size")?;
Expand Down Expand Up @@ -128,6 +135,7 @@ fn calculate_host_function_soroban_resources(
ledger_changes: &[LedgerEntryChange],
footprint: &Footprint,
budget: &Budget,
resource_config: CResourceConfig,
) -> Result<SorobanResources> {
let ledger_footprint = storage_footprint_to_ledger_footprint(footprint)
.context("cannot convert storage footprint to ledger footprint")?;
Expand All @@ -143,7 +151,7 @@ fn calculate_host_function_soroban_resources(
.get_cpu_insns_consumed()
.context("cannot get instructions consumed")?;
let instructions = max(
budget_instructions + 3000000,
budget_instructions + resource_config.instruction_leeway,
budget_instructions * 120 / 100,
);
Ok(SorobanResources {
Expand Down
10 changes: 10 additions & 0 deletions cmd/soroban-rpc/lib/preflight/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ fn get_default_c_xdr_vector() -> CXDRVector {
}
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CResourceConfig {
pub instruction_leeway: u64,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CPreflightResult {
Expand Down Expand Up @@ -133,6 +139,7 @@ pub extern "C" fn preflight_invoke_hf_op(
invoke_hf_op: CXDR, // InvokeHostFunctionOp XDR in base64
source_account: CXDR, // AccountId XDR in base64
ledger_info: CLedgerInfo,
resource_config: CResourceConfig,
enable_debug: bool,
) -> *mut CPreflightResult {
catch_preflight_panic(Box::new(move || {
Expand All @@ -142,6 +149,7 @@ pub extern "C" fn preflight_invoke_hf_op(
invoke_hf_op,
source_account,
ledger_info,
resource_config,
enable_debug,
)
}))
Expand All @@ -153,6 +161,7 @@ fn preflight_invoke_hf_op_or_maybe_panic(
invoke_hf_op: CXDR, // InvokeHostFunctionOp XDR in base64
source_account: CXDR, // AccountId XDR in base64
ledger_info: CLedgerInfo,
resource_config: CResourceConfig,
enable_debug: bool,
) -> Result<CPreflightResult> {
let invoke_hf_op =
Expand All @@ -166,6 +175,7 @@ fn preflight_invoke_hf_op_or_maybe_panic(
invoke_hf_op,
source_account,
LedgerInfo::from(ledger_info),
resource_config,
enable_debug,
)?;
Ok(result.into())
Expand Down
4 changes: 4 additions & 0 deletions cmd/soroban-rpc/lib/preflight/src/preflight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use std::convert::{TryFrom, TryInto};
use std::iter::FromIterator;
use std::rc::Rc;

use crate::CResourceConfig;

pub(crate) struct RestorePreamble {
pub(crate) transaction_data: SorobanTransactionData,
pub(crate) min_fee: i64,
Expand All @@ -40,6 +42,7 @@ pub(crate) fn preflight_invoke_hf_op(
invoke_hf_op: InvokeHostFunctionOp,
source_account: AccountId,
ledger_info: LedgerInfo,
resource_config: CResourceConfig,
enable_debug: bool,
) -> Result<PreflightResult> {
let ledger_storage_rc = Rc::new(ledger_storage);
Expand Down Expand Up @@ -117,6 +120,7 @@ pub(crate) fn preflight_invoke_hf_op(
&ledger_storage_rc,
&storage,
&budget,
resource_config,
&diagnostic_events,
&result,
bucket_list_size,
Expand Down

0 comments on commit 9ea424d

Please sign in to comment.