Skip to content

Commit

Permalink
Release/v0.4.2 (#559)
Browse files Browse the repository at this point in the history
* Validation for uploaded DTL address lists (#538)

(cherry picked from commit 733276c)

* change: remove use etherscan on client to fetch unrelative txs (#541)

(cherry picked from commit 3d2b9d1)

* Revert "patch proxyd validId (#543)" (#547)

This reverts commit aa4a7fd.

(cherry picked from commit fabbf36)

* Add gascap and check input on hybrid compute and add unit tests (#553)

(cherry picked from commit 61b1e85)

Co-authored-by: cby3149 <[email protected]>
(cherry picked from commit abf05cc)

---------

Co-authored-by: Michael Montour <[email protected]>
Co-authored-by: Sahil K <[email protected]>
  • Loading branch information
3 people authored Feb 2, 2023
1 parent edd21de commit 7eb7fb0
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 191 deletions.
208 changes: 104 additions & 104 deletions go/proxyd/integration_tests/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,94 +13,94 @@ const (
notWhitelistedResponse = `{"jsonrpc":"2.0","error":{"code":-32001,"message":"rpc method is not whitelisted custom message"},"id":999}`
parseErrResponse = `{"jsonrpc":"2.0","error":{"code":-32700,"message":"parse error"},"id":null}`
invalidJSONRPCVersionResponse = `{"error":{"code":-32601,"message":"invalid JSON-RPC version"},"id":null,"jsonrpc":"2.0"}`
//invalidIDResponse = `{"error":{"code":-32601,"message":"invalid ID"},"id":null,"jsonrpc":"2.0"}`
invalidMethodResponse = `{"error":{"code":-32601,"message":"no method specified"},"id":null,"jsonrpc":"2.0"}`
invalidBatchLenResponse = `{"error":{"code":-32601,"message":"must specify at least one batch call"},"id":null,"jsonrpc":"2.0"}`
invalidIDResponse = `{"error":{"code":-32601,"message":"invalid ID"},"id":null,"jsonrpc":"2.0"}`
invalidMethodResponse = `{"error":{"code":-32601,"message":"no method specified"},"id":null,"jsonrpc":"2.0"}`
invalidBatchLenResponse = `{"error":{"code":-32601,"message":"must specify at least one batch call"},"id":null,"jsonrpc":"2.0"}`
)

// func TestSingleRPCValidation(t *testing.T) {
// goodBackend := NewMockBackend(BatchedResponseHandler(200, goodResponse))
// defer goodBackend.Close()
func TestSingleRPCValidation(t *testing.T) {
goodBackend := NewMockBackend(BatchedResponseHandler(200, goodResponse))
defer goodBackend.Close()

// require.NoError(t, os.Setenv("GOOD_BACKEND_RPC_URL", goodBackend.URL()))
require.NoError(t, os.Setenv("GOOD_BACKEND_RPC_URL", goodBackend.URL()))

// config := ReadConfig("whitelist")
// client := NewProxydClient("http://127.0.0.1:8545")
// shutdown, err := proxyd.Start(config)
// require.NoError(t, err)
// defer shutdown()
config := ReadConfig("whitelist")
client := NewProxydClient("http://127.0.0.1:8545")
shutdown, err := proxyd.Start(config)
require.NoError(t, err)
defer shutdown()

// tests := []struct {
// name string
// body string
// res string
// code int
// }{
// {
// "body not JSON",
// "this ain't an RPC call",
// parseErrResponse,
// 400,
// },
// {
// "body not RPC",
// "{\"not\": \"rpc\"}",
// invalidJSONRPCVersionResponse,
// 400,
// },
// // {
// // "body missing RPC ID",
// // "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23]}",
// // invalidIDResponse,
// // 400,
// // },
// {
// "body has array ID",
// "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": []}",
// invalidIDResponse,
// 400,
// },
// {
// "body has object ID",
// "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": {}}",
// invalidIDResponse,
// 400,
// },
// {
// "bad method",
// "{\"jsonrpc\": \"2.0\", \"method\": 7, \"params\": [42, 23], \"id\": 1}",
// parseErrResponse,
// 400,
// },
// {
// "bad JSON-RPC",
// "{\"jsonrpc\": \"1.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": 1}",
// invalidJSONRPCVersionResponse,
// 400,
// },
// {
// "omitted method",
// "{\"jsonrpc\": \"2.0\", \"params\": [42, 23], \"id\": 1}",
// invalidMethodResponse,
// 400,
// },
// {
// "not whitelisted method",
// "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": 999}",
// notWhitelistedResponse,
// 403,
// },
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// res, code, err := client.SendRequest([]byte(tt.body))
// require.NoError(t, err)
// RequireEqualJSON(t, []byte(tt.res), res)
// require.Equal(t, tt.code, code)
// require.Equal(t, 0, len(goodBackend.Requests()))
// })
// }
// }
tests := []struct {
name string
body string
res string
code int
}{
{
"body not JSON",
"this ain't an RPC call",
parseErrResponse,
400,
},
{
"body not RPC",
"{\"not\": \"rpc\"}",
invalidJSONRPCVersionResponse,
400,
},
{
"body missing RPC ID",
"{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23]}",
invalidIDResponse,
400,
},
{
"body has array ID",
"{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": []}",
invalidIDResponse,
400,
},
{
"body has object ID",
"{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": {}}",
invalidIDResponse,
400,
},
{
"bad method",
"{\"jsonrpc\": \"2.0\", \"method\": 7, \"params\": [42, 23], \"id\": 1}",
parseErrResponse,
400,
},
{
"bad JSON-RPC",
"{\"jsonrpc\": \"1.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": 1}",
invalidJSONRPCVersionResponse,
400,
},
{
"omitted method",
"{\"jsonrpc\": \"2.0\", \"params\": [42, 23], \"id\": 1}",
invalidMethodResponse,
400,
},
{
"not whitelisted method",
"{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": 999}",
notWhitelistedResponse,
403,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res, code, err := client.SendRequest([]byte(tt.body))
require.NoError(t, err)
RequireEqualJSON(t, []byte(tt.res), res)
require.Equal(t, tt.code, code)
require.Equal(t, 0, len(goodBackend.Requests()))
})
}
}

func TestBatchRPCValidation(t *testing.T) {
goodBackend := NewMockBackend(BatchedResponseHandler(200, goodResponse))
Expand Down Expand Up @@ -149,27 +149,27 @@ func TestBatchRPCValidation(t *testing.T) {
200,
0,
},
// {
// "body missing RPC ID",
// "[{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23]}]",
// asArray(invalidIDResponse),
// 200,
// 0,
// },
// {
// "body has array ID",
// "[{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": []}]",
// asArray(invalidIDResponse),
// 200,
// 0,
// },
// {
// "body has object ID",
// "[{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": {}}]",
// asArray(invalidIDResponse),
// 200,
// 0,
// },
{
"body missing RPC ID",
"[{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23]}]",
asArray(invalidIDResponse),
200,
0,
},
{
"body has array ID",
"[{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": []}]",
asArray(invalidIDResponse),
200,
0,
},
{
"body has object ID",
"[{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": {}}]",
asArray(invalidIDResponse),
200,
0,
},
// this happens because we can't deserialize the method into a non
// string value, and it blows up the parsing for the whole request.
{
Expand Down
7 changes: 3 additions & 4 deletions go/proxyd/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,9 @@ func ValidateRPCReq(req *RPCReq) error {
return ErrInvalidRequest("no method specified")
}

// cosmic universe
// if !IsValidID(req.ID) {
// return ErrInvalidRequest("invalid ID")
// }
if !IsValidID(req.ID) {
return ErrInvalidRequest("invalid ID")
}

return nil
}
Expand Down
104 changes: 104 additions & 0 deletions l2geth/boba/boba_turing_call_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package boba

import (
"errors"
"math/big"
"testing"

"github.com/ethereum-optimism/optimism/l2geth/common"
"github.com/ethereum-optimism/optimism/l2geth/common/hexutil"
"github.com/ethereum-optimism/optimism/l2geth/core"
"github.com/ethereum-optimism/optimism/l2geth/core/rawdb"
"github.com/ethereum-optimism/optimism/l2geth/core/state"
"github.com/ethereum-optimism/optimism/l2geth/core/vm"
"github.com/ethereum-optimism/optimism/l2geth/crypto"
"github.com/ethereum-optimism/optimism/l2geth/params"
"github.com/ethereum-optimism/optimism/l2geth/tests"
)

var (
ErrTuringInputTooShort = errors.New("turing input too short")
ErrTuringEmpty = errors.New("turing replay data not found")
contractAddr = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
EOAAddr = common.HexToAddress("0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266")
)

type ContractRef struct{}

func (ContractRef) Address() common.Address { return contractAddr }

func vmTestBlockHash(n uint64) common.Hash {
return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
}

func newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {
initialCall := true
canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool {
if initialCall {
initialCall = false
return true
}
return core.CanTransfer(db, address, amount)
}
transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {}
context := vm.Context{
CanTransfer: canTransfer,
Transfer: transfer,
GetHash: vmTestBlockHash,
Origin: EOAAddr,
Coinbase: EOAAddr,
BlockNumber: new(big.Int).SetUint64(0),
Time: new(big.Int).SetUint64(0),
GasLimit: 0,
Difficulty: common.Big1,
GasPrice: common.Big1,
}
vmconfig.NoRecursion = true
return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig)
}

func createStateDB() *state.StateDB {
alloc := core.GenesisAlloc{}
alloc[contractAddr] = core.GenesisAccount{
Nonce: 1,
Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"),
Balance: big.NewInt(1),
}
statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc)
return statedb
}

func TestHybridComputeShortInput(t *testing.T) {
errTuringInput := []byte{125, 147, 97, 108}
TuringInput := append(errTuringInput[:], make([]byte, 32)...)
statedb := createStateDB()
evm := newEVM(statedb, vm.Config{})
if _, _, err := evm.Call(ContractRef{}, EOAAddr, errTuringInput, 0, common.Big0); err == ErrTuringInputTooShort {
t.Fatalf("should return 'turing input too short', but got err %v", err)
}
if _, _, err := evm.Call(ContractRef{}, EOAAddr, TuringInput, 0, common.Big0); err == ErrTuringEmpty {
t.Fatalf("should return 'turing replay data not found', but got err %v", err)
}
}

func TestHybridComputeGetRandomShortInput(t *testing.T) {
errGetRandInput := []byte{73, 61, 87, 214}
getRandInputInput := append(errGetRandInput[:], make([]byte, 32)...)
statedb := createStateDB()
evm := newEVM(statedb, vm.Config{})
if _, _, err := evm.Call(ContractRef{}, EOAAddr, errGetRandInput, 0, common.Big0); err == ErrTuringInputTooShort {
t.Fatalf("should return 'turing input too short', but got err %v", err)
}
if _, _, err := evm.Call(ContractRef{}, EOAAddr, getRandInputInput, 0, common.Big0); err == ErrTuringEmpty {
t.Fatalf("should return 'turing replay data not found', but got err %v", err)
}
}

func TestShortInput(t *testing.T) {
standardInput := []byte{0, 0, 0, 0}
statedb := createStateDB()
evm := newEVM(statedb, vm.Config{})
if _, _, err := evm.Call(ContractRef{}, EOAAddr, standardInput, 0, common.Big0); err != nil {
t.Fatalf("should return nil, but got err %v", err)
}
}
1 change: 1 addition & 0 deletions l2geth/core/vm/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ var (
ErrTuringEmpty = errors.New("turing replay data not found")
ErrTuringTooLong = errors.New("turing calldata too long for gas")
ErrGasUintOverflow = errors.New("gas uint64 overflow")
ErrTuringInputTooShort = errors.New("turing input too short")
)
5 changes: 5 additions & 0 deletions l2geth/core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if isTuring2 || isGetRand2 {
prefix_str = "TURING"
log.Debug("TURING REQUEST START", "input", hexutil.Bytes(input), "len(evm.Context.Turing)", len(evm.Context.Turing))
// Check 0. the payload must be at least 36 bytes long
if len(input) < 36 {
log.Error("TURING ERROR: INPUT TOO SHORT", "input", input)
return nil, gas, ErrTuringInputTooShort
}
// Check 1. can only run Turing once anywhere in the call stack
if evm.Context.TuringDepth > 1 {
log.Error("TURING ERROR: DEPTH > 1", "evm.Context.TuringDepth", evm.Context.TuringDepth)
Expand Down
1 change: 1 addition & 0 deletions ops/scripts/geth.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ exec geth \
--mine \
--miner.etherbase $BLOCK_SIGNER_ADDRESS \
--rangelimit \
--rpc.gascap ${GAS_CAP:-11000000} \
"$@"
1 change: 0 additions & 1 deletion packages/boba/gateway/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
REACT_APP_INFURA_ID=
REACT_APP_ETHERSCAN_API=
REACT_APP_POLL_INTERVAL=15000
REACT_APP_GAS_POLL_INTERVAL=30000
SKIP_PREFLIGHT_CHECK=true
Expand Down
1 change: 0 additions & 1 deletion packages/boba/gateway/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ gateway.boba.betwork.
| Environment Vars | Required | Default Valu | Description |
| ---------------------------- | -------- | ------------ | --------------------------------------------------------------- |
| REACT_APP_INFURA_ID | Yes | '' | API key for infura account |
| REACT_APP_ETHERSCAN_API | Yes | '' | API key for etherscan acount. |
| REACT_APP_POLL_INTERVAL | Yes | 20000 | Interval to poll the fetch api about the records |
| SKIP_PREFLIGHT_CHECK | N/A | N/A | N/A |
| REACT_APP_WALLET_VERSION | Yes | N/A | This will be useful while prepare the build. |
Expand Down
Loading

0 comments on commit 7eb7fb0

Please sign in to comment.