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: Add getPreflight benchmark and test #692

Merged
merged 7 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/soroban-rpc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ jobs:
- uses: ./.github/actions/setup-go
with:
go-version: ${{ matrix.go }}
- run: |
- name: Build soroban contract fixtures
2opremio marked this conversation as resolved.
Show resolved Hide resolved
run: |
rustup update
rustup target add wasm32-unknown-unknown
make build-test-wasms
2opremio marked this conversation as resolved.
Show resolved Hide resolved
- run: make build-libpreflight
- run: go test -race -cover -timeout 25m -v ./cmd/soroban-rpc/...

Expand Down
331 changes: 331 additions & 0 deletions cmd/soroban-rpc/internal/preflight/preflight_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,331 @@
package preflight

import (
"context"
"os"
"path"
"runtime"
"testing"

"github.com/stellar/go/support/log"
"github.com/stellar/go/xdr"
"github.com/stretchr/testify/require"

"github.com/stellar/soroban-tools/cmd/soroban-rpc/internal/db"
)

var mockContractID = xdr.Hash{0xa, 0xb, 0xc}
var mockContractHash = xdr.Hash{0xd, 0xe, 0xf}

var contractCostParams = func() *xdr.ContractCostParams {
var result xdr.ContractCostParams

for i := 0; i < 22; i++ {
result = append(result, xdr.ContractCostParamEntry{
Ext: xdr.ExtensionPoint{},
ConstTerm: 0,
LinearTerm: 0,
})
}

return &result
}()

var mockLedgerEntries = []xdr.LedgerEntry{
{
LastModifiedLedgerSeq: 1,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeContractData,
ContractData: &xdr.ContractDataEntry{
Contract: xdr.ScAddress{
Type: xdr.ScAddressTypeScAddressTypeContract,
ContractId: &mockContractID,
},
Key: xdr.ScVal{
Type: xdr.ScValTypeScvLedgerKeyContractInstance,
},
Durability: xdr.ContractDataDurabilityPersistent,
ExpirationLedgerSeq: 100000,
Body: xdr.ContractDataEntryBody{
BodyType: xdr.ContractEntryBodyTypeDataEntry,
Data: &xdr.ContractDataEntryData{
Flags: 0,
Val: xdr.ScVal{
Type: xdr.ScValTypeScvContractInstance,
Instance: &xdr.ScContractInstance{
Executable: xdr.ContractExecutable{
Type: xdr.ContractExecutableTypeContractExecutableWasm,
WasmHash: &mockContractHash,
},
Storage: nil,
},
},
},
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeContractCode,
ContractCode: &xdr.ContractCodeEntry{
Hash: mockContractHash,
Body: xdr.ContractCodeEntryBody{
BodyType: xdr.ContractEntryBodyTypeDataEntry,
Code: &helloWorldContract,
},
ExpirationLedgerSeq: 20000,
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractComputeV0,
ContractCompute: &xdr.ConfigSettingContractComputeV0{
LedgerMaxInstructions: 100000000,
TxMaxInstructions: 100000000,
FeeRatePerInstructionsIncrement: 1,
TxMemoryLimit: 100000000,
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractLedgerCostV0,
ContractLedgerCost: &xdr.ConfigSettingContractLedgerCostV0{
LedgerMaxReadLedgerEntries: 100,
LedgerMaxReadBytes: 100,
LedgerMaxWriteLedgerEntries: 100,
LedgerMaxWriteBytes: 100,
TxMaxReadLedgerEntries: 100,
TxMaxReadBytes: 100,
TxMaxWriteLedgerEntries: 100,
TxMaxWriteBytes: 100,
FeeReadLedgerEntry: 100,
FeeWriteLedgerEntry: 100,
FeeRead1Kb: 100,
BucketListTargetSizeBytes: 100,
WriteFee1KbBucketListLow: 1,
WriteFee1KbBucketListHigh: 1,
BucketListWriteFeeGrowthFactor: 1,
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractHistoricalDataV0,
ContractHistoricalData: &xdr.ConfigSettingContractHistoricalDataV0{
FeeHistorical1Kb: 100,
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractMetaDataV0,
ContractMetaData: &xdr.ConfigSettingContractMetaDataV0{
TxMaxExtendedMetaDataSizeBytes: 100,
FeeExtendedMetaData1Kb: 100,
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractBandwidthV0,
ContractBandwidth: &xdr.ConfigSettingContractBandwidthV0{
LedgerMaxPropagateSizeBytes: 100,
TxMaxSizeBytes: 100,
FeePropagateData1Kb: 100,
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingStateExpiration,
StateExpirationSettings: &xdr.StateExpirationSettings{
MaxEntryExpiration: 100,
MinTempEntryExpiration: 100,
MinPersistentEntryExpiration: 100,
AutoBumpLedgers: 100,
PersistentRentRateDenominator: 100,
TempRentRateDenominator: 100,
MaxEntriesToExpire: 100,
BucketListSizeWindowSampleSize: 100,
EvictionScanSize: 100,
},
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractCostParamsCpuInstructions,
// Obtained with TestGetLedgerEntryConfigSettings
ContractCostParamsCpuInsns: contractCostParams,
},
},
},
{
LastModifiedLedgerSeq: 2,
Data: xdr.LedgerEntryData{
Type: xdr.LedgerEntryTypeConfigSetting,
ConfigSetting: &xdr.ConfigSettingEntry{
ConfigSettingId: xdr.ConfigSettingIdConfigSettingContractCostParamsMemoryBytes,
// Obtained with TestGetLedgerEntryConfigSettings
ContractCostParamsMemBytes: contractCostParams,
},
},
},
}

var helloWorldContract = func() []byte {
_, filename, _, _ := runtime.Caller(0)
testDirName := path.Dir(filename)
contractFile := path.Join(testDirName, "../../../../target/wasm32-unknown-unknown/test-wasms/test_hello_world.wasm")
ret, err := os.ReadFile(contractFile)
if err != nil {
log.Fatalf("unable to read test_hello_world.wasm (%v) please run `make build-test-wasms` at the project root directory", err)
}
return ret
}()

type inMemoryLedgerEntryReadTx map[string]xdr.LedgerEntry

func newInMemoryLedgerEntryReadTx(entries []xdr.LedgerEntry) (inMemoryLedgerEntryReadTx, error) {
result := make(map[string]xdr.LedgerEntry, len(entries))
for _, entry := range entries {
key, err := entry.LedgerKey()
if err != nil {
return inMemoryLedgerEntryReadTx{}, err
}
serialized, err := key.MarshalBinaryBase64()
if err != nil {
return inMemoryLedgerEntryReadTx{}, err
}
result[serialized] = entry
}
return result, nil
}

func (m inMemoryLedgerEntryReadTx) GetLatestLedgerSequence() (uint32, error) {
return 2, nil
}

func (m inMemoryLedgerEntryReadTx) GetLedgerEntry(key xdr.LedgerKey, includeExpired bool) (bool, xdr.LedgerEntry, error) {
serializedKey, err := key.MarshalBinaryBase64()
if err != nil {
return false, xdr.LedgerEntry{}, err
}
entry, ok := m[serializedKey]
if !ok {
return false, xdr.LedgerEntry{}, nil
}
return true, entry, nil
}

func (m inMemoryLedgerEntryReadTx) Done() error {
return nil
}

func getPreflightParameters(t testing.TB, inMemory bool) PreflightParameters {
var ledgerEntryReadTx db.LedgerEntryReadTx
if inMemory {
var err error
ledgerEntryReadTx, err = newInMemoryLedgerEntryReadTx(mockLedgerEntries)
require.NoError(t, err)
} else {
d := t.TempDir()
dbInstance, err := db.OpenSQLiteDB(path.Join(d, "soroban_rpc.sqlite"))
require.NoError(t, err)
readWriter := db.NewReadWriter(dbInstance, 100, 10000)
tx, err := readWriter.NewTx(context.Background())
require.NoError(t, err)
for _, e := range mockLedgerEntries {
err := tx.LedgerEntryWriter().UpsertLedgerEntry(e)
require.NoError(t, err)
}
err = tx.Commit(2)
require.NoError(t, err)
ledgerEntryReadTx, err = db.NewLedgerEntryReader(dbInstance).NewTx(context.Background())
require.NoError(t, err)
}
argSymbol := xdr.ScSymbol("world")
params := PreflightParameters{
Logger: log.New(),
SourceAccount: xdr.MustAddress("GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H"),
OpBody: xdr.OperationBody{Type: xdr.OperationTypeInvokeHostFunction,
InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{
HostFunction: xdr.HostFunction{
Type: xdr.HostFunctionTypeHostFunctionTypeInvokeContract,
InvokeContract: &xdr.InvokeContractArgs{
ContractAddress: xdr.ScAddress{
Type: xdr.ScAddressTypeScAddressTypeContract,
ContractId: &mockContractID,
},
FunctionName: "hello",
Args: []xdr.ScVal{
{
Type: xdr.ScValTypeScvSymbol,
Sym: &argSymbol,
},
},
},
},
}},
NetworkPassphrase: "foo",
LedgerEntryReadTx: ledgerEntryReadTx,
BucketListSize: 200,
}
return params
}

func TestGetPreflight(t *testing.T) {
params := getPreflightParameters(t, false)
_, err := GetPreflight(context.Background(), params)
require.NoError(t, err)

params = getPreflightParameters(t, true)
_, err = GetPreflight(context.Background(), params)
require.NoError(t, err)
}

func benchmark(b *testing.B, inMemory bool) {
params := getPreflightParameters(b, inMemory)
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StartTimer()
_, err := GetPreflight(context.Background(), params)
b.StopTimer()
require.NoError(b, err)
}
}

func BenchmarkGetPreflight(b *testing.B) {
b.Run("In-memory storage", func(b *testing.B) { benchmark(b, true) })
b.Run("DB storage", func(b *testing.B) { benchmark(b, false) })
}
2 changes: 1 addition & 1 deletion cmd/soroban-rpc/internal/test/get_ledger_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
"github.com/creachadair/jrpc2"
"github.com/creachadair/jrpc2/code"
"github.com/creachadair/jrpc2/jhttp"
"github.com/stellar/go/txnbuild"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stellar/go/keypair"
"github.com/stellar/go/txnbuild"
"github.com/stellar/go/xdr"

"github.com/stellar/soroban-tools/cmd/soroban-rpc/internal/methods"
Expand Down