Skip to content

Commit

Permalink
- fix executor to prevent the case it can not execute transaction due…
Browse files Browse the repository at this point in the history
… to higher than allowed gas limit provided
  • Loading branch information
iulianpascalau committed Oct 17, 2024
1 parent fb74091 commit f6967af
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 153 deletions.
3 changes: 2 additions & 1 deletion cmd/scCallsExecutor/config/config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ScProxyBech32Address = "erd1qqqqqqqqqqqqqpgqnef5f5aq32d63kljld8w5vnvz4gk5sy9hrrq2ld08s"
ExtraGasToExecute = 60000000 #this value allow the SC calls without provided gas limit to be refunded
ExtraGasToExecute = 60000000 # this value allow the SC calls without provided gas limit to be refunded
MaxGasLimitToUse = 249999999 # this is a safe max gas limit to use both intra-shard & cross-shard
GasLimitForOutOfGasTransactions = 30000000 # this value will be used when a transaction specified a gas limit > 249999999
NetworkAddress = "http://127.0.0.1:8085"
ProxyMaxNoncesDelta = 7
ProxyFinalityCheck = true
Expand Down
29 changes: 15 additions & 14 deletions cmd/scCallsExecutor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,21 @@ func startExecutor(ctx *cli.Context, version string) error {
}

args := config.ScCallsModuleConfig{
ScProxyBech32Address: cfg.ScProxyBech32Address,
ExtraGasToExecute: cfg.ExtraGasToExecute,
MaxGasLimitToUse: cfg.MaxGasLimitToUse,
NetworkAddress: cfg.NetworkAddress,
ProxyMaxNoncesDelta: cfg.ProxyMaxNoncesDelta,
ProxyFinalityCheck: cfg.ProxyFinalityCheck,
ProxyCacherExpirationSeconds: cfg.ProxyCacherExpirationSeconds,
ProxyRestAPIEntityType: cfg.ProxyRestAPIEntityType,
IntervalToResendTxsInSeconds: cfg.IntervalToResendTxsInSeconds,
PrivateKeyFile: cfg.PrivateKeyFile,
PollingIntervalInMillis: cfg.PollingIntervalInMillis,
Filter: cfg.Filter,
Logs: cfg.Logs,
TransactionChecks: cfg.TransactionChecks,
ScProxyBech32Address: cfg.ScProxyBech32Address,
ExtraGasToExecute: cfg.ExtraGasToExecute,
MaxGasLimitToUse: cfg.MaxGasLimitToUse,
GasLimitForOutOfGasTransactions: cfg.GasLimitForOutOfGasTransactions,
NetworkAddress: cfg.NetworkAddress,
ProxyMaxNoncesDelta: cfg.ProxyMaxNoncesDelta,
ProxyFinalityCheck: cfg.ProxyFinalityCheck,
ProxyCacherExpirationSeconds: cfg.ProxyCacherExpirationSeconds,
ProxyRestAPIEntityType: cfg.ProxyRestAPIEntityType,
IntervalToResendTxsInSeconds: cfg.IntervalToResendTxsInSeconds,
PrivateKeyFile: cfg.PrivateKeyFile,
PollingIntervalInMillis: cfg.PollingIntervalInMillis,
Filter: cfg.Filter,
Logs: cfg.Logs,
TransactionChecks: cfg.TransactionChecks,
}

chCloseApp := make(chan struct{}, 1)
Expand Down
29 changes: 15 additions & 14 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,20 +192,21 @@ type PendingOperationsFilterConfig struct {

// ScCallsModuleConfig will hold the settings for the SC calls module
type ScCallsModuleConfig struct {
ScProxyBech32Address string
ExtraGasToExecute uint64
MaxGasLimitToUse uint64
NetworkAddress string
ProxyMaxNoncesDelta int
ProxyFinalityCheck bool
ProxyCacherExpirationSeconds uint64
ProxyRestAPIEntityType string
IntervalToResendTxsInSeconds uint64
PrivateKeyFile string
PollingIntervalInMillis uint64
Filter PendingOperationsFilterConfig
Logs LogsConfig
TransactionChecks TransactionChecksConfig
ScProxyBech32Address string
ExtraGasToExecute uint64
MaxGasLimitToUse uint64
GasLimitForOutOfGasTransactions uint64
NetworkAddress string
ProxyMaxNoncesDelta int
ProxyFinalityCheck bool
ProxyCacherExpirationSeconds uint64
ProxyRestAPIEntityType string
IntervalToResendTxsInSeconds uint64
PrivateKeyFile string
PollingIntervalInMillis uint64
Filter PendingOperationsFilterConfig
Logs LogsConfig
TransactionChecks TransactionChecksConfig
}

// TransactionChecksConfig will hold the setting for how to handle the transaction execution
Expand Down
24 changes: 13 additions & 11 deletions config/tomlConfigs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,17 +405,18 @@ func TestScCallsExecutorConfigs(t *testing.T) {
t.Parallel()

expectedConfig := ScCallsModuleConfig{
ScProxyBech32Address: "erd1qqqqqqqqqqqqqpgqnef5f5aq32d63kljld8w5vnvz4gk5sy9hrrq2ld08s",
ExtraGasToExecute: 50000000,
MaxGasLimitToUse: 249999999,
NetworkAddress: "127.0.0.1:8085",
ProxyMaxNoncesDelta: 7,
ProxyFinalityCheck: true,
ProxyCacherExpirationSeconds: 600,
ProxyRestAPIEntityType: "observer",
IntervalToResendTxsInSeconds: 60,
PrivateKeyFile: "keys/multiversx.pem",
PollingIntervalInMillis: 6000,
ScProxyBech32Address: "erd1qqqqqqqqqqqqqpgqnef5f5aq32d63kljld8w5vnvz4gk5sy9hrrq2ld08s",
ExtraGasToExecute: 50000000,
MaxGasLimitToUse: 249999999,
GasLimitForOutOfGasTransactions: 30000000,
NetworkAddress: "127.0.0.1:8085",
ProxyMaxNoncesDelta: 7,
ProxyFinalityCheck: true,
ProxyCacherExpirationSeconds: 600,
ProxyRestAPIEntityType: "observer",
IntervalToResendTxsInSeconds: 60,
PrivateKeyFile: "keys/multiversx.pem",
PollingIntervalInMillis: 6000,
Filter: PendingOperationsFilterConfig{
AllowedEthAddresses: []string{"*"},
AllowedMvxAddresses: []string{"*"},
Expand All @@ -438,6 +439,7 @@ func TestScCallsExecutorConfigs(t *testing.T) {
ScProxyBech32Address = "erd1qqqqqqqqqqqqqpgqnef5f5aq32d63kljld8w5vnvz4gk5sy9hrrq2ld08s"
ExtraGasToExecute = 50000000
MaxGasLimitToUse = 249999999 # this is a safe max gas limit to use both intra-shard & cross-shard
GasLimitForOutOfGasTransactions = 30000000 # this value will be used when a transaction specified a gas limit > 249999999
NetworkAddress = "127.0.0.1:8085"
ProxyMaxNoncesDelta = 7
ProxyFinalityCheck = true
Expand Down
24 changes: 12 additions & 12 deletions executors/multiversx/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package multiversx
import "errors"

var (
errInvalidNumberOfResponseLines = errors.New("invalid number of responses")
errNilProxy = errors.New("nil proxy")
errNilCodec = errors.New("nil codec")
errNilFilter = errors.New("nil filter")
errNilLogger = errors.New("nil logger")
errNilNonceTxHandler = errors.New("nil nonce transaction handler")
errNilPrivateKey = errors.New("nil private key")
errNilSingleSigner = errors.New("nil single signer")
errInvalidValue = errors.New("invalid value")
errNilCloseAppChannel = errors.New("nil close application channel")
errTransactionFailed = errors.New("transaction failed")
errMaxGasLimitIsLessThanRequired = errors.New("max gas limit to execute a SC call is less than the minimum required")
errInvalidNumberOfResponseLines = errors.New("invalid number of responses")
errNilProxy = errors.New("nil proxy")
errNilCodec = errors.New("nil codec")
errNilFilter = errors.New("nil filter")
errNilLogger = errors.New("nil logger")
errNilNonceTxHandler = errors.New("nil nonce transaction handler")
errNilPrivateKey = errors.New("nil private key")
errNilSingleSigner = errors.New("nil single signer")
errInvalidValue = errors.New("invalid value")
errNilCloseAppChannel = errors.New("nil close application channel")
errTransactionFailed = errors.New("transaction failed")
errGasLimitIsLessThanAbsoluteMinimum = errors.New("provided gas limit is less than absolute minimum required")
)
25 changes: 13 additions & 12 deletions executors/multiversx/module/scCallsModule.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,19 @@ func NewScCallsModule(cfg config.ScCallsModuleConfig, log logger.Logger, chClose
}

argsExecutor := multiversx.ArgsScCallExecutor{
ScProxyBech32Address: cfg.ScProxyBech32Address,
Proxy: proxy,
Codec: &parsers.MultiversxCodec{},
Filter: filter,
Log: log,
ExtraGasToExecute: cfg.ExtraGasToExecute,
MaxGasLimitToUse: cfg.MaxGasLimitToUse,
NonceTxHandler: module.nonceTxsHandler,
PrivateKey: privateKey,
SingleSigner: singleSigner,
CloseAppChan: chCloseApp,
TransactionChecks: cfg.TransactionChecks,
ScProxyBech32Address: cfg.ScProxyBech32Address,
Proxy: proxy,
Codec: &parsers.MultiversxCodec{},
Filter: filter,
Log: log,
ExtraGasToExecute: cfg.ExtraGasToExecute,
MaxGasLimitToUse: cfg.MaxGasLimitToUse,
GasLimitForOutOfGasTransactions: cfg.GasLimitForOutOfGasTransactions,
NonceTxHandler: module.nonceTxsHandler,
PrivateKey: privateKey,
SingleSigner: singleSigner,
CloseAppChan: chCloseApp,
TransactionChecks: cfg.TransactionChecks,
}
module.executorInstance, err = multiversx.NewScCallExecutor(argsExecutor)
if err != nil {
Expand Down
27 changes: 16 additions & 11 deletions executors/multiversx/module/scCallsModule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ import (

func createTestConfigs() config.ScCallsModuleConfig {
return config.ScCallsModuleConfig{
ScProxyBech32Address: "erd1qqqqqqqqqqqqqpgqgftcwj09u0nhmskrw7xxqcqh8qmzwyexd8ss7ftcxx",
ExtraGasToExecute: 6000000,
MaxGasLimitToUse: 249999999,
NetworkAddress: "http://127.0.0.1:8079",
ProxyMaxNoncesDelta: 5,
ProxyFinalityCheck: false,
ProxyCacherExpirationSeconds: 60,
ProxyRestAPIEntityType: string(sdkCore.ObserverNode),
IntervalToResendTxsInSeconds: 1,
PrivateKeyFile: "testdata/grace.pem",
PollingIntervalInMillis: 10000,
ScProxyBech32Address: "erd1qqqqqqqqqqqqqpgqgftcwj09u0nhmskrw7xxqcqh8qmzwyexd8ss7ftcxx",
ExtraGasToExecute: 6000000,
MaxGasLimitToUse: 249999999,
GasLimitForOutOfGasTransactions: 30000000,
NetworkAddress: "http://127.0.0.1:8079",
ProxyMaxNoncesDelta: 5,
ProxyFinalityCheck: false,
ProxyCacherExpirationSeconds: 60,
ProxyRestAPIEntityType: string(sdkCore.ObserverNode),
IntervalToResendTxsInSeconds: 1,
PrivateKeyFile: "testdata/grace.pem",
PollingIntervalInMillis: 10000,
Filter: config.PendingOperationsFilterConfig{
DeniedEthAddresses: nil,
AllowedEthAddresses: []string{"*"},
Expand Down Expand Up @@ -98,6 +99,8 @@ func TestNewScCallsModule(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, module)

assert.Zero(t, module.GetNumSentTransaction())

err = module.Close()
assert.Nil(t, err)
})
Expand All @@ -113,6 +116,8 @@ func TestNewScCallsModule(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, module)

assert.Zero(t, module.GetNumSentTransaction())

err = module.Close()
assert.Nil(t, err)
})
Expand Down
123 changes: 73 additions & 50 deletions executors/multiversx/scCallsExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,46 @@ const (
minCheckValues = 1
transactionNotFoundErrString = "transaction not found"
minGasToExecuteSCCalls = 2010000 // the absolut minimum gas limit to do a SC call
contractMaxGasLimit = 249999999
)

// ArgsScCallExecutor represents the DTO struct for creating a new instance of type scCallExecutor
type ArgsScCallExecutor struct {
ScProxyBech32Address string
Proxy Proxy
Codec Codec
Filter ScCallsExecuteFilter
Log logger.Logger
ExtraGasToExecute uint64
MaxGasLimitToUse uint64
NonceTxHandler NonceTransactionsHandler
PrivateKey crypto.PrivateKey
SingleSigner crypto.SingleSigner
TransactionChecks config.TransactionChecksConfig
CloseAppChan chan struct{}
ScProxyBech32Address string
Proxy Proxy
Codec Codec
Filter ScCallsExecuteFilter
Log logger.Logger
ExtraGasToExecute uint64
MaxGasLimitToUse uint64
GasLimitForOutOfGasTransactions uint64
NonceTxHandler NonceTransactionsHandler
PrivateKey crypto.PrivateKey
SingleSigner crypto.SingleSigner
TransactionChecks config.TransactionChecksConfig
CloseAppChan chan struct{}
}

type scCallExecutor struct {
scProxyBech32Address string
proxy Proxy
codec Codec
filter ScCallsExecuteFilter
log logger.Logger
extraGasToExecute uint64
maxGasLimitToUse uint64
nonceTxHandler NonceTransactionsHandler
privateKey crypto.PrivateKey
singleSigner crypto.SingleSigner
senderAddress core.AddressHandler
numSentTransactions uint32
checkTransactionResults bool
timeBetweenChecks time.Duration
executionTimeout time.Duration
closeAppOnError bool
extraDelayOnError time.Duration
closeAppChan chan struct{}
scProxyBech32Address string
proxy Proxy
codec Codec
filter ScCallsExecuteFilter
log logger.Logger
extraGasToExecute uint64
maxGasLimitToUse uint64
gasLimitForOutOfGasTransactions uint64
nonceTxHandler NonceTransactionsHandler
privateKey crypto.PrivateKey
singleSigner crypto.SingleSigner
senderAddress core.AddressHandler
numSentTransactions uint32
checkTransactionResults bool
timeBetweenChecks time.Duration
executionTimeout time.Duration
closeAppOnError bool
extraDelayOnError time.Duration
closeAppChan chan struct{}
}

// NewScCallExecutor creates a new instance of type scCallExecutor
Expand All @@ -82,23 +85,24 @@ func NewScCallExecutor(args ArgsScCallExecutor) (*scCallExecutor, error) {
senderAddress := data.NewAddressFromBytes(publicKeyBytes)

return &scCallExecutor{
scProxyBech32Address: args.ScProxyBech32Address,
proxy: args.Proxy,
codec: args.Codec,
filter: args.Filter,
log: args.Log,
extraGasToExecute: args.ExtraGasToExecute,
maxGasLimitToUse: args.MaxGasLimitToUse,
nonceTxHandler: args.NonceTxHandler,
privateKey: args.PrivateKey,
singleSigner: args.SingleSigner,
senderAddress: senderAddress,
checkTransactionResults: args.TransactionChecks.CheckTransactionResults,
timeBetweenChecks: time.Second * time.Duration(args.TransactionChecks.TimeInSecondsBetweenChecks),
executionTimeout: time.Second * time.Duration(args.TransactionChecks.ExecutionTimeoutInSeconds),
closeAppOnError: args.TransactionChecks.CloseAppOnError,
extraDelayOnError: time.Second * time.Duration(args.TransactionChecks.ExtraDelayInSecondsOnError),
closeAppChan: args.CloseAppChan,
scProxyBech32Address: args.ScProxyBech32Address,
proxy: args.Proxy,
codec: args.Codec,
filter: args.Filter,
log: args.Log,
extraGasToExecute: args.ExtraGasToExecute,
maxGasLimitToUse: args.MaxGasLimitToUse,
gasLimitForOutOfGasTransactions: args.GasLimitForOutOfGasTransactions,
nonceTxHandler: args.NonceTxHandler,
privateKey: args.PrivateKey,
singleSigner: args.SingleSigner,
senderAddress: senderAddress,
checkTransactionResults: args.TransactionChecks.CheckTransactionResults,
timeBetweenChecks: time.Second * time.Duration(args.TransactionChecks.TimeInSecondsBetweenChecks),
executionTimeout: time.Second * time.Duration(args.TransactionChecks.ExecutionTimeoutInSeconds),
closeAppOnError: args.TransactionChecks.CloseAppOnError,
extraDelayOnError: time.Second * time.Duration(args.TransactionChecks.ExtraDelayInSecondsOnError),
closeAppChan: args.CloseAppChan,
}, nil
}

Expand All @@ -125,7 +129,10 @@ func checkArgs(args ArgsScCallExecutor) error {
return errNilSingleSigner
}
if args.MaxGasLimitToUse < minGasToExecuteSCCalls {
return fmt.Errorf("%w: provided: %d, absolute minimum required: %d", errMaxGasLimitIsLessThanRequired, args.MaxGasLimitToUse, minGasToExecuteSCCalls)
return fmt.Errorf("%w for MaxGasLimitToUse: provided: %d, absolute minimum required: %d", errGasLimitIsLessThanAbsoluteMinimum, args.MaxGasLimitToUse, minGasToExecuteSCCalls)
}
if args.GasLimitForOutOfGasTransactions < minGasToExecuteSCCalls {
return fmt.Errorf("%w for GasLimitForOutOfGasTransactions: provided: %d, absolute minimum required: %d", errGasLimitIsLessThanAbsoluteMinimum, args.GasLimitForOutOfGasTransactions, minGasToExecuteSCCalls)
}
err := checkTransactionChecksConfig(args)
if err != nil {
Expand Down Expand Up @@ -287,8 +294,23 @@ func (executor *scCallExecutor) executeOperation(
Value: "0",
}

to, _ := callData.To.AddressAsBech32String()
if tx.GasLimit > contractMaxGasLimit {
// the contract will refund this transaction, so we will use less gas to preserve funds
executor.log.Warn("setting a lower gas limit for this transaction because it will be refunded",
"computed gas limit", tx.GasLimit,
"max allowed", executor.maxGasLimitToUse,
"data", dataBytes,
"from", callData.From.Hex(),
"to", to,
"token", callData.Token,
"amount", callData.Amount,
"nonce", callData.Nonce,
)
tx.GasLimit = executor.gasLimitForOutOfGasTransactions
}

if tx.GasLimit > executor.maxGasLimitToUse {
to, _ := callData.To.AddressAsBech32String()
executor.log.Warn("can not execute transaction because the provided gas limit on the SC call exceeds "+
"the maximum gas limit allowance for this executor, WILL SKIP the execution",
"computed gas limit", tx.GasLimit,
Expand Down Expand Up @@ -324,7 +346,8 @@ func (executor *scCallExecutor) executeOperation(
"tx ID", id,
"call data", callData.String(),
"extra gas", executor.extraGasToExecute,
"sender", bech32Address)
"sender", bech32Address,
"to", to)

atomic.AddUint32(&executor.numSentTransactions, 1)

Expand Down
Loading

0 comments on commit f6967af

Please sign in to comment.