Skip to content

Commit

Permalink
fix: allow empty to field in eth_call to simulate contract deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
CedarMist committed Mar 31, 2024
1 parent 59e6ad5 commit 79182c5
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 16 deletions.
6 changes: 3 additions & 3 deletions conf/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ database:
max_open_conns: 0

gateway:
chain_id: 42262
chain_id: 23293
http:
host: "localhost"
port: 8545
port: 8945
ws:
host: "localhost"
port: 8546
port: 8946
monitoring:
host: "localhost"
port: 9999
Expand Down
5 changes: 5 additions & 0 deletions docker/common/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ notice "Waiting for Oasis node to start..."
while [[ ! -S ${OASIS_NODE_SOCKET} ]]; do echo -n .; sleep 1; done
echo

chmod 755 /serverdir/node/net-runner/
chmod 755 /serverdir/node/net-runner/network/
chmod 755 /serverdir/node/net-runner/network/client-0/
chmod a+rw /serverdir/node/net-runner/network/client-0/internal.sock

notice "Starting oasis-web3-gateway...\n"
${OASIS_WEB3_GATEWAY} --config ${OASIS_WEB3_GATEWAY_CONFIG_FILE} 2>1 &>/var/log/oasis-web3-gateway.log &
OASIS_WEB3_GATEWAY_PID=$!
Expand Down
24 changes: 13 additions & 11 deletions rpc/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,13 @@ func (api *publicAPI) Call(ctx context.Context, args utils.TransactionArgs, bloc
sender = common.Address{1}
gasPrice = []byte{1}
// This gas cap should be enough for SimulateCall an ethereum transaction
gas uint64 = 30_000_000
gas uint64 = 30_000_000
toBytes = []byte{}
)

if args.To == nil {
return []byte{}, errors.New("to address not specified")
// When simulating a contract deploy the To address may not be specified
if args.To != nil {
toBytes = args.To.Bytes()
}
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt().Bytes()
Expand All @@ -396,14 +398,14 @@ func (api *publicAPI) Call(ctx context.Context, args utils.TransactionArgs, bloc
}

res, err := evm.NewV1(api.client).SimulateCall(
ctx,
round,
gasPrice,
gas,
sender.Bytes(),
args.To.Bytes(),
amount,
input,
ctx, // context
round, // round
gasPrice, // gasPrice
gas, // gasLimit
sender.Bytes(), // caller
toBytes, // address
amount, // value
input, // data
)
if err != nil {
return nil, api.handleCallFailure(ctx, logger, err)
Expand Down
1 change: 1 addition & 0 deletions tests/rpc/contracts/evm_constructor_require.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6080604052348015600e575f80fd5b5060405162461bcd60e51b815260206004820152601360248201527f4578616d706c654572726f725265717569726500000000000000000000000000604482015260640160405180910390fdfe
1 change: 1 addition & 0 deletions tests/rpc/contracts/evm_constructor_revert.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6080604052348015600e575f80fd5b5060405163547796ff60e01b815260206004820152601260248201527122bc30b6b83632a1bab9ba37b6a2b93937b960711b604482015260640160405180910390fdfe
112 changes: 112 additions & 0 deletions tests/rpc/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
_ "embed"
"math/big"
"reflect"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -71,6 +72,117 @@ func waitTransaction(ctx context.Context, ec *ethclient.Client, txhash common.Ha
}
}

/*
contract ExampleRequire {
constructor () {
require(false, "ExampleErrorRequire");
}
}
*/
//go:embed contracts/evm_constructor_require.hex
var evmConstructorRequireHex string

/*
contract ExampleCustomError {
error Example(string x);
constructor () {
revert Example("ExampleCustomError");
}
}
*/
//go:embed contracts/evm_constructor_revert.hex
var evmConstructorRevertHex string

// extractDataFromUnexportedError extracts the "Data" field from *rpc.jsonError that is not exported
// using reflection.
func extractDataFromUnexportedError(err error) string {
if err == nil {
return ""
}

val := reflect.ValueOf(err)
if val.Kind() == reflect.Ptr && !val.IsNil() {
// Assuming jsonError is a struct
errVal := val.Elem()

// Check if the struct has a field named "Data".
dataField := errVal.FieldByName("Data")
if dataField.IsValid() && dataField.CanInterface() {
// Assuming the data field is a string
return dataField.Interface().(string)
}
}

return ""
}

// Verifies that require(false,"...") in constructor works as expected

Check failure on line 119 in tests/rpc/tx_test.go

View workflow job for this annotation

GitHub Actions / lint-go

Comment should end in a period (godot)
func testContractConstructorError(t *testing.T, contractCode string, expectedError string) {
ec := localClient(t, false)

t.Logf("compiled contract: %s", contractCode)
code := common.FromHex(strings.TrimSpace(contractCode))

callMsg := ethereum.CallMsg{
From: tests.TestKey1.EthAddress,
Gas: 0,
Data: code,
}

// Estimate contract creation gas requirements
gasCost, err := ec.EstimateGas(context.Background(), callMsg)
require.Nil(t, err, "estimate gas failed")
require.Greater(t, gasCost, uint64(0), "gas estimate must be positive")
t.Logf("gas estimate for contract creation: %d", gasCost)

// Evaluate the contract creation via `eth_call`
callMsg.Gas = 250000 // gasCost
result, err := ec.CallContract(context.Background(), callMsg, nil)
require.NotNil(t, err, "constructor expected to throw error")
require.Equal(t, expectedError, extractDataFromUnexportedError(err))
require.Nil(t, result)
}

func TestContractConstructorRequire(t *testing.T) {
testContractConstructorError(t, evmConstructorRequireHex, "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000134578616d706c654572726f725265717569726500000000000000000000000000")
}

func TestContractConstructorRevert(t *testing.T) {
testContractConstructorError(t, evmConstructorRevertHex, "0x547796ff000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000124578616d706c65437573746f6d4572726f720000000000000000000000000000")
}

// Verify contract creation can be simulated and returns an address

Check failure on line 154 in tests/rpc/tx_test.go

View workflow job for this annotation

GitHub Actions / lint-go

Comment should end in a period (godot)
func TestContractCreateInCall(t *testing.T) {
ec := localClient(t, false)

t.Logf("compiled contract: %s", evmSolTestCompiledHex)
code := common.FromHex(strings.TrimSpace(evmSolTestCompiledHex))

gasPrice, err := ec.SuggestGasPrice(context.Background())
require.Nil(t, err, "get gasPrice failed")

callMsg := ethereum.CallMsg{
From: tests.TestKey1.EthAddress,
Gas: 0,
GasPrice: gasPrice,
Data: code,
}

// Estimate contract creation gas requirements
gasCost, err := ec.EstimateGas(context.Background(), callMsg)
require.NoError(t, err, "estimate gas failed")
require.Greater(t, gasCost, uint64(0), "gas estimate must be positive")
t.Logf("gas estimate for contract creation: %d", gasCost)

// Evaluate the contract creation via `eth_call`
callMsg.Gas = 250000 // gasCost
result, err := ec.CallContract(context.Background(), callMsg, nil)
require.Nil(t, err, "call contract")

require.NotNil(t, result)
require.Equal(t, len(result), 20)
}

func testContractCreation(t *testing.T, value *big.Int) uint64 {
ec := localClient(t, false)

Expand Down
8 changes: 6 additions & 2 deletions tests/tools/spinup-oasis-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ function paratime_ver {
export FIXTURE_FILE="${OASIS_NODE_DATADIR}/fixture.json"
export STAKING_GENESIS_FILE="$(dirname "$0")/staking_genesis.json"

rm -rf "$OASIS_NODE_DATADIR"
mkdir -p "$OASIS_NODE_DATADIR"
rm -rf "$OASIS_NODE_DATADIR/net-runner" || true
rm -rf "$OASIS_NODE_DATADIR/net-runner.log" || true
rm -rf "$OASIS_NODE_DATADIR/fixture.json" || true
# When $OASIS_NODE_DATADIR is bind-mounted, below fails, but the above succeed
rm -rf "$OASIS_NODE_DATADIR" || true
mkdir -p "$OASIS_NODE_DATADIR" || true

# Prepare configuration for oasis-node (fixture).
${OASIS_NET_RUNNER} dump-fixture \
Expand Down

0 comments on commit 79182c5

Please sign in to comment.