Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

soroban-rpc: Allow Budget Instruction Leeway to be Configured by Clients #1131

Merged
merged 10 commits into from
Dec 15, 2023
7 changes: 4 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, readTx db.LedgerEntryReadTx, bucketListSize uint64, sourceAccount xdr.AccountId, opBody xdr.OperationBody, footprint xdr.LedgerFootprint, resourceConfig *preflight.ResourceConfig) (preflight.Preflight, error)
stellarsaur marked this conversation as resolved.
Show resolved Hide resolved
}

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

result, err := getter.GetPreflight(ctx, readTx, bucketListSize, sourceAccount, op.Body, footprint)
result, err := getter.GetPreflight(ctx, readTx, bucketListSize, sourceAccount, op.Body, footprint, request.ResourceConfig)
if err != nil {
return SimulateTransactionResponse{
Error: err.Error(),
Expand Down
3 changes: 2 additions & 1 deletion cmd/soroban-rpc/internal/preflight/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ 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, readTx db.LedgerEntryReadTx, bucketListSize uint64, sourceAccount xdr.AccountId, opBody xdr.OperationBody, footprint xdr.LedgerFootprint, resourceConfig *ResourceConfig) (Preflight, error) {
if pwp.isClosed.Load() {
return Preflight{}, errors.New("preflight worker pool is closed")
}
Expand All @@ -154,6 +154,7 @@ func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, readTx db.Ledg
LedgerEntryReadTx: &wrappedTx,
BucketListSize: bucketListSize,
Footprint: footprint,
ResourceConfig: resourceConfig,
EnableDebug: pwp.enableDebug,
}
resultC := make(chan workerResult)
Expand Down
17 changes: 17 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 = 1000000
)

// 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,10 @@ func FreeGoXDR(xdr C.xdr_t) {
C.free(unsafe.Pointer(xdr.xdr))
}

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

type PreflightParameters struct {
Logger *log.Entry
SourceAccount xdr.AccountId
Expand All @@ -79,6 +87,7 @@ type PreflightParameters struct {
NetworkPassphrase string
LedgerEntryReadTx db.LedgerEntryReadTx
BucketListSize uint64
ResourceConfig *ResourceConfig
stellarsaur marked this conversation as resolved.
Show resolved Hide resolved
EnableDebug bool
}

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

handle := cgo.NewHandle(snapshotSourceHandle{params.LedgerEntryReadTx, params.Logger})
defer handle.Delete()
instructionLeeway := defaultInstructionLeeway
if params.ResourceConfig != nil {
instructionLeeway = params.ResourceConfig.InstructionLeeway
}
resourceConfig := C.resource_config_t{
instruction_leeway: C.uint64_t(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 + 1000000,
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
Loading