Skip to content

Commit

Permalink
soroban-rpc: simulateTransaction: automatically detect ledger entries…
Browse files Browse the repository at this point in the history
… which require restoring (#865)

This change incorporates a new field to the simulateTransactionResponse:

```
RestorePreamble RestorePreamble              `json:"restorePreamble,omitempty"`
```

where:

```
type RestorePreamble struct {
	TransactionData string `json:"transactionData"` // SorobanTransactionData XDR in base64
	MinResourceFee  int64  `json:"minResourceFee,string"`
}
```

When preflighting an InvokeHostFunction operation, soroban-rpc will
now detect ledger entries which require restoring prior to the
invocation for it to succeed.

If any such entries are detected, the simulateTransaction response
will provide the Soroban Transaction Data and minimum resource fee
needed to restore those entries.

The user is then now expected to:
1. Submit a RestoreFootprint operation using the new fields above, if present.
2. Submit the InvokeHostFunction operation normally.
  • Loading branch information
2opremio authored Aug 18, 2023
1 parent 8ed9813 commit 08de7d5
Show file tree
Hide file tree
Showing 11 changed files with 384 additions and 207 deletions.
37 changes: 27 additions & 10 deletions cmd/soroban-rpc/internal/methods/simulate_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ type SimulateHostFunctionResult struct {
XDR string `json:"xdr"`
}

type RestorePreamble struct {
TransactionData string `json:"transactionData"` // SorobanTransactionData XDR in base64
MinResourceFee int64 `json:"minResourceFee,string"`
}

type SimulateTransactionResponse struct {
Error string `json:"error,omitempty"`
TransactionData string `json:"transactionData"` // SorobanTransactionData XDR in base64
Events []string `json:"events"` // DiagnosticEvent XDR in base64
MinResourceFee int64 `json:"minResourceFee,string"`
Results []SimulateHostFunctionResult `json:"results,omitempty"` // an array of the individual host function call results
Cost SimulateTransactionCost `json:"cost"` // the effective cpu and memory cost of the invoked transaction execution.
Events []string `json:"events,omitempty"` // DiagnosticEvent XDR in base64
Results []SimulateHostFunctionResult `json:"results,omitempty"` // an array of the individual host function call results
Cost SimulateTransactionCost `json:"cost"` // the effective cpu and memory cost of the invoked transaction execution.
RestorePreamble RestorePreamble `json:"restorePreamble,omitempty"` // If present, it indicates that a prior RestoreFootprint is required
LatestLedger int64 `json:"latestLedger,string"`
}

Expand Down Expand Up @@ -114,21 +120,32 @@ func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.Ledge
}
}

var results []SimulateHostFunctionResult
if result.Result != "" {
results = append(results, SimulateHostFunctionResult{
XDR: result.Result,
Auth: result.Auth,
})
}
restorePreable := RestorePreamble{}
if result.PreRestoreTransactionData != "" {
restorePreable = RestorePreamble{
TransactionData: result.PreRestoreTransactionData,
MinResourceFee: result.PreRestoreMinFee,
}
}

return SimulateTransactionResponse{
Results: []SimulateHostFunctionResult{
{
XDR: result.Result,
Auth: result.Auth,
},
},
Results: results,
Events: result.Events,
TransactionData: result.TransactionData,
MinResourceFee: result.MinFee,
Cost: SimulateTransactionCost{
CPUInstructions: result.CPUInstructions,
MemoryBytes: result.MemoryBytes,
},
LatestLedger: int64(latestLedger),
LatestLedger: int64(latestLedger),
RestorePreamble: restorePreable,
}
})
}
Expand Down
54 changes: 18 additions & 36 deletions cmd/soroban-rpc/internal/preflight/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,28 +61,6 @@ func SnapshotSourceGet(handle C.uintptr_t, cLedgerKey *C.char, includeExpired C.
return C.CString(out)
}

// SnapshotSourceHas takes LedgerKey XDR in base64 and returns whether it exists
// It's used by the Rust preflight code to obtain ledger entries.
//
//export SnapshotSourceHas
func SnapshotSourceHas(handle C.uintptr_t, cLedgerKey *C.char) C.int {
h := cgo.Handle(handle).Value().(snapshotSourceHandle)
ledgerKeyB64 := C.GoString(cLedgerKey)
var ledgerKey xdr.LedgerKey
if err := xdr.SafeUnmarshalBase64(ledgerKeyB64, &ledgerKey); err != nil {
panic(err)
}
present, _, err := h.readTx.GetLedgerEntry(ledgerKey, false)
if err != nil {
h.logger.WithError(err).Error("SnapshotSourceHas(): GetLedgerEntry() failed")
return 0
}
if present {
return 1
}
return 0
}

//export FreeGoCString
func FreeGoCString(str *C.char) {
C.free(unsafe.Pointer(str))
Expand All @@ -99,13 +77,15 @@ type PreflightParameters struct {
}

type Preflight struct {
Events []string // DiagnosticEvents XDR in base64
TransactionData string // SorobanTransactionData XDR in base64
MinFee int64
Result string // XDR SCVal in base64
Auth []string // SorobanAuthorizationEntrys XDR in base64
CPUInstructions uint64
MemoryBytes uint64
Events []string // DiagnosticEvents XDR in base64
TransactionData string // SorobanTransactionData XDR in base64
MinFee int64
Result string // XDR SCVal in base64
Auth []string // SorobanAuthorizationEntrys XDR in base64
CPUInstructions uint64
MemoryBytes uint64
PreRestoreTransactionData string // SorobanTransactionData XDR in base64
PreRestoreMinFee int64
}

// GoNullTerminatedStringSlice transforms a C NULL-terminated char** array to a Go string slice
Expand Down Expand Up @@ -240,13 +220,15 @@ func GoPreflight(result *C.CPreflightResult) (Preflight, error) {
}

preflight := Preflight{
Events: GoNullTerminatedStringSlice(result.events),
TransactionData: C.GoString(result.transaction_data),
MinFee: int64(result.min_fee),
Result: C.GoString(result.result),
Auth: GoNullTerminatedStringSlice(result.auth),
CPUInstructions: uint64(result.cpu_instructions),
MemoryBytes: uint64(result.memory_bytes),
Events: GoNullTerminatedStringSlice(result.events),
TransactionData: C.GoString(result.transaction_data),
MinFee: int64(result.min_fee),
Result: C.GoString(result.result),
Auth: GoNullTerminatedStringSlice(result.auth),
CPUInstructions: uint64(result.cpu_instructions),
MemoryBytes: uint64(result.memory_bytes),
PreRestoreTransactionData: C.GoString(result.pre_restore_transaction_data),
PreRestoreMinFee: int64(result.pre_restore_min_fee),
}
return preflight, nil
}
1 change: 1 addition & 0 deletions cmd/soroban-rpc/internal/preflight/preflight_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ func getPreflightParameters(t testing.TB, inMemory bool) PreflightParameters {
}

func TestGetPreflight(t *testing.T) {

params := getPreflightParameters(t, false)
_, err := GetPreflight(context.Background(), params)
require.NoError(t, err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ FAILURE_SAFETY=0
ENABLE_SOROBAN_DIAGNOSTIC_EVENTS=true
# Lower the expiration of persistent ledger entries
# so that ledger expiration/restoring becomes testeable
TESTING_MINIMUM_PERSISTENT_ENTRY_LIFETIME=20
TESTING_MINIMUM_PERSISTENT_ENTRY_LIFETIME=10

[[VALIDATORS]]
NAME="local_core"
Expand Down
Loading

0 comments on commit 08de7d5

Please sign in to comment.