From 0f26e0d67bbc4244ae74cf67d6e358fa2849d891 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 21 Apr 2023 16:23:16 +0800 Subject: [PATCH 1/7] test(integration): pre-deploy test contracts into genesis (#420) Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- Jenkinsfile | 1 + common/bytecode/.gitignore | 2 + common/bytecode/Makefile | 9 + common/bytecode/README.md | 40 +++ common/bytecode/erc20/ERC20Mock.json | 387 +++++++++++++++++++++++ common/bytecode/greeter/Greeter.json | 72 +++++ common/docker/l1geth/genesis.json | 12 +- common/docker/l2geth/genesis.json | 21 +- tests/integration-test/contracts_test.go | 28 ++ 9 files changed, 569 insertions(+), 3 deletions(-) create mode 100644 common/bytecode/.gitignore create mode 100644 common/bytecode/Makefile create mode 100644 common/bytecode/README.md create mode 100644 common/bytecode/erc20/ERC20Mock.json create mode 100644 common/bytecode/greeter/Greeter.json create mode 100644 tests/integration-test/contracts_test.go diff --git a/Jenkinsfile b/Jenkinsfile index 274ef2001..78ea3a35a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -24,6 +24,7 @@ pipeline { steps { sh 'make dev_docker' sh 'make -C bridge mock_abi' + sh 'make -C common/bytecode all' } } stage('Check Bridge Compilation') { diff --git a/common/bytecode/.gitignore b/common/bytecode/.gitignore new file mode 100644 index 000000000..1ea16914d --- /dev/null +++ b/common/bytecode/.gitignore @@ -0,0 +1,2 @@ +*.go +*.sol \ No newline at end of file diff --git a/common/bytecode/Makefile b/common/bytecode/Makefile new file mode 100644 index 000000000..38f635302 --- /dev/null +++ b/common/bytecode/Makefile @@ -0,0 +1,9 @@ +.PHONY: all erc20 greeter + +all: erc20 greeter + +erc20: + go run github.com/scroll-tech/go-ethereum/cmd/abigen --combined-json ./erc20/ERC20Mock.json --pkg erc20 --out ./erc20/ERC20Mock.go + +greeter: + go run github.com/scroll-tech/go-ethereum/cmd/abigen --combined-json ./greeter/Greeter.json --pkg greeter --out ./greeter/Greeter.go diff --git a/common/bytecode/README.md b/common/bytecode/README.md new file mode 100644 index 000000000..794bd1069 --- /dev/null +++ b/common/bytecode/README.md @@ -0,0 +1,40 @@ +## How to pre deploy contracts? +* Please reference to https://github.com/scroll-tech/genesis-creator. +1. Setup env +```bash + git clone git@github.com:scroll-tech/genesis-creator.git + cd genesis-creator + go get -v github.com/scroll-tech/go-ethereum@develop && go mod tidy + make abi && make genesis-creator + make l2geth-docker +``` + +2. Start docker and write pre deployed contracts into genesis file. +```bash + make start-docker + ./bin/genesis-creator -genesis ${SCROLLPATH}/common/docker/l2geth/genesis.json -contract [erc20|greeter] +``` + +3. Rebuild l2geth docker. +```bash + cd ${SCROLLPATH} + make dev_docker +``` + +## How to get contract abi? +* Other contracts' step same to eth20, e.g: +1. Install solc. + + *Reference to https://docs.soliditylang.org/en/latest/installing-solidity.html* + +2. Get abi file. +```bash + cd genesis-creator + solc --combined-json "abi" --optimize ${SCROLLPATH}/common/bytecode/erc20/ERC20Mock.sol | jq > ${SCROLLPATH}/common/bytecode/erc20/ERC20Mock.json +``` + +3. Translate abi to go. +```bash + cd ${SCROLLPATH} + make -C common/bytecode all +``` diff --git a/common/bytecode/erc20/ERC20Mock.json b/common/bytecode/erc20/ERC20Mock.json new file mode 100644 index 000000000..41fd24e23 --- /dev/null +++ b/common/bytecode/erc20/ERC20Mock.json @@ -0,0 +1,387 @@ +{ + "contracts": { + "tests/contracts/erc20/erc20.sol:ERC20Mock": { + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "address", + "name": "initialAccount", + "type": "address" + }, + { + "internalType": "uint256", + "name": "initialBalance", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approveInternal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferInternal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] + } + }, + "version": "0.8.16+commit.07a7930e.Darwin.appleclang" +} diff --git a/common/bytecode/greeter/Greeter.json b/common/bytecode/greeter/Greeter.json new file mode 100644 index 000000000..48c64257a --- /dev/null +++ b/common/bytecode/greeter/Greeter.json @@ -0,0 +1,72 @@ +{ + "contracts": { + "greeter/Greeter.sol:Greeter": { + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "num", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "retrieve", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "retrieve_failing", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "num", + "type": "uint256" + } + ], + "name": "set_value", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "num", + "type": "uint256" + } + ], + "name": "set_value_failing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] + } + }, + "version": "0.8.16+commit.07a7930e.Darwin.appleclang" +} diff --git a/common/docker/l1geth/genesis.json b/common/docker/l1geth/genesis.json index 06bac78d3..0ceec2348 100644 --- a/common/docker/l1geth/genesis.json +++ b/common/docker/l1geth/genesis.json @@ -21,13 +21,23 @@ "nonce": "0x0", "timestamp": "0x61bc34a0", "extraData": "0x00000000000000000000000000000000000000000000000000000000000000001c5a77d9fa7ef466951b2f01f724bca3a5820b630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "940000000000000", + "gasLimit": "0x356ecce16c000", "difficulty": "0x1", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "alloc": { "1c5a77d9fa7ef466951b2f01f724bca3a5820b63": { "balance": "0x200000000000000000000000000000000000000000000000000000000000000" + }, + "7363726f6c6c6c20000000000000000000000014": { + "code": "0x608060405234801561001057600080fd5b50600436106100f55760003560e01c806340c10f19116100975780639dc29fac116100665780639dc29fac14610286578063a457c2d7146102a2578063a9059cbb146102d2578063dd62ed3e14610302576100f5565b806340c10f191461020057806356189cb41461021c57806370a082311461023857806395d89b4114610268576100f5565b8063222f5be0116100d3578063222f5be01461016657806323b872dd14610182578063313ce567146101b257806339509351146101d0576100f5565b806306fdde03146100fa578063095ea7b31461011857806318160ddd14610148575b600080fd5b610102610332565b60405161010f9190610f27565b60405180910390f35b610132600480360381019061012d9190610fe2565b6103c4565b60405161013f919061103d565b60405180910390f35b6101506103e7565b60405161015d9190611067565b60405180910390f35b610180600480360381019061017b9190611082565b6103f1565b005b61019c60048036038101906101979190611082565b610401565b6040516101a9919061103d565b60405180910390f35b6101ba610430565b6040516101c791906110f1565b60405180910390f35b6101ea60048036038101906101e59190610fe2565b610439565b6040516101f7919061103d565b60405180910390f35b61021a60048036038101906102159190610fe2565b610470565b005b61023660048036038101906102319190611082565b61047e565b005b610252600480360381019061024d919061110c565b61048e565b60405161025f9190611067565b60405180910390f35b6102706104d6565b60405161027d9190610f27565b60405180910390f35b6102a0600480360381019061029b9190610fe2565b610568565b005b6102bc60048036038101906102b79190610fe2565b610576565b6040516102c9919061103d565b60405180910390f35b6102ec60048036038101906102e79190610fe2565b6105ed565b6040516102f9919061103d565b60405180910390f35b61031c60048036038101906103179190611139565b610610565b6040516103299190611067565b60405180910390f35b606060038054610341906111a8565b80601f016020809104026020016040519081016040528092919081815260200182805461036d906111a8565b80156103ba5780601f1061038f576101008083540402835291602001916103ba565b820191906000526020600020905b81548152906001019060200180831161039d57829003601f168201915b5050505050905090565b6000806103cf610697565b90506103dc81858561069f565b600191505092915050565b6000600254905090565b6103fc838383610868565b505050565b60008061040c610697565b9050610419858285610ade565b610424858585610868565b60019150509392505050565b60006012905090565b600080610444610697565b90506104658185856104568589610610565b6104609190611208565b61069f565b600191505092915050565b61047a8282610b6a565b5050565b61048983838361069f565b505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060600480546104e5906111a8565b80601f0160208091040260200160405190810160405280929190818152602001828054610511906111a8565b801561055e5780601f106105335761010080835404028352916020019161055e565b820191906000526020600020905b81548152906001019060200180831161054157829003601f168201915b5050505050905090565b6105728282610cc0565b5050565b600080610581610697565b9050600061058f8286610610565b9050838110156105d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cb906112ae565b60405180910390fd5b6105e1828686840361069f565b60019250505092915050565b6000806105f8610697565b9050610605818585610868565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361070e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070590611340565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361077d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610774906113d2565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405161085b9190611067565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ce90611464565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610946576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093d906114f6565b60405180910390fd5b610951838383610e8d565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611588565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ac59190611067565b60405180910390a3610ad8848484610e92565b50505050565b6000610aea8484610610565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610b645781811015610b56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4d906115f4565b60405180910390fd5b610b63848484840361069f565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd090611660565b60405180910390fd5b610be560008383610e8d565b8060026000828254610bf79190611208565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610ca89190611067565b60405180910390a3610cbc60008383610e92565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610d2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d26906116f2565b60405180910390fd5b610d3b82600083610e8d565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610dc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db890611784565b60405180910390fd5b8181036000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610e749190611067565b60405180910390a3610e8883600084610e92565b505050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ed1578082015181840152602081019050610eb6565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ef982610e97565b610f038185610ea2565b9350610f13818560208601610eb3565b610f1c81610edd565b840191505092915050565b60006020820190508181036000830152610f418184610eee565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610f7982610f4e565b9050919050565b610f8981610f6e565b8114610f9457600080fd5b50565b600081359050610fa681610f80565b92915050565b6000819050919050565b610fbf81610fac565b8114610fca57600080fd5b50565b600081359050610fdc81610fb6565b92915050565b60008060408385031215610ff957610ff8610f49565b5b600061100785828601610f97565b925050602061101885828601610fcd565b9150509250929050565b60008115159050919050565b61103781611022565b82525050565b6000602082019050611052600083018461102e565b92915050565b61106181610fac565b82525050565b600060208201905061107c6000830184611058565b92915050565b60008060006060848603121561109b5761109a610f49565b5b60006110a986828701610f97565b93505060206110ba86828701610f97565b92505060406110cb86828701610fcd565b9150509250925092565b600060ff82169050919050565b6110eb816110d5565b82525050565b600060208201905061110660008301846110e2565b92915050565b60006020828403121561112257611121610f49565b5b600061113084828501610f97565b91505092915050565b600080604083850312156111505761114f610f49565b5b600061115e85828601610f97565b925050602061116f85828601610f97565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806111c057607f821691505b6020821081036111d3576111d2611179565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061121382610fac565b915061121e83610fac565b9250828201905080821115611236576112356111d9565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000611298602583610ea2565b91506112a38261123c565b604082019050919050565b600060208201905081810360008301526112c78161128b565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b600061132a602483610ea2565b9150611335826112ce565b604082019050919050565b600060208201905081810360008301526113598161131d565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b60006113bc602283610ea2565b91506113c782611360565b604082019050919050565b600060208201905081810360008301526113eb816113af565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b600061144e602583610ea2565b9150611459826113f2565b604082019050919050565b6000602082019050818103600083015261147d81611441565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b60006114e0602383610ea2565b91506114eb82611484565b604082019050919050565b6000602082019050818103600083015261150f816114d3565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000611572602683610ea2565b915061157d82611516565b604082019050919050565b600060208201905081810360008301526115a181611565565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b60006115de601d83610ea2565b91506115e9826115a8565b602082019050919050565b6000602082019050818103600083015261160d816115d1565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600061164a601f83610ea2565b915061165582611614565b602082019050919050565b600060208201905081810360008301526116798161163d565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b60006116dc602183610ea2565b91506116e782611680565b604082019050919050565b6000602082019050818103600083015261170b816116cf565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b600061176e602283610ea2565b915061177982611712565b604082019050919050565b6000602082019050818103600083015261179d81611761565b905091905056fea26469706673582212206a0466cc8279c36801cc7618e809890da047e4518cddd96836b2e2250be5535764736f6c63430008100033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000204fce5e3e25020000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x4554480000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x45544820636f696e000000000000000000000000000000000000000000000010", + "0x62a9a27ba8ad7d7d9c6567de722ea497f95a95e67f937096a94d55dbefc0109b": "0x0000000000000000000000000000000000000000204fce5e3e25020000000000" + }, + "balance": "0x0" } }, "number": "0x0", diff --git a/common/docker/l2geth/genesis.json b/common/docker/l2geth/genesis.json index 49c209ebd..2437c2da3 100644 --- a/common/docker/l2geth/genesis.json +++ b/common/docker/l2geth/genesis.json @@ -21,17 +21,34 @@ "nonce": "0x0", "timestamp": "0x61bc34a0", "extraData": "0x00000000000000000000000000000000000000000000000000000000000000001c5a77d9fa7ef466951b2f01f724bca3a5820b630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "940000000000000", + "gasLimit": "8000000", "difficulty": "0x1", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "alloc": { "1c5a77d9fa7ef466951b2f01f724bca3a5820b63": { "balance": "0x200000000000000000000000000000000000000000000000000000000000000" + }, + "7363726f6c6c6c20000000000000000000000014": { + "code": "0x608060405234801561001057600080fd5b50600436106100f55760003560e01c806340c10f19116100975780639dc29fac116100665780639dc29fac14610286578063a457c2d7146102a2578063a9059cbb146102d2578063dd62ed3e14610302576100f5565b806340c10f191461020057806356189cb41461021c57806370a082311461023857806395d89b4114610268576100f5565b8063222f5be0116100d3578063222f5be01461016657806323b872dd14610182578063313ce567146101b257806339509351146101d0576100f5565b806306fdde03146100fa578063095ea7b31461011857806318160ddd14610148575b600080fd5b610102610332565b60405161010f9190610f27565b60405180910390f35b610132600480360381019061012d9190610fe2565b6103c4565b60405161013f919061103d565b60405180910390f35b6101506103e7565b60405161015d9190611067565b60405180910390f35b610180600480360381019061017b9190611082565b6103f1565b005b61019c60048036038101906101979190611082565b610401565b6040516101a9919061103d565b60405180910390f35b6101ba610430565b6040516101c791906110f1565b60405180910390f35b6101ea60048036038101906101e59190610fe2565b610439565b6040516101f7919061103d565b60405180910390f35b61021a60048036038101906102159190610fe2565b610470565b005b61023660048036038101906102319190611082565b61047e565b005b610252600480360381019061024d919061110c565b61048e565b60405161025f9190611067565b60405180910390f35b6102706104d6565b60405161027d9190610f27565b60405180910390f35b6102a0600480360381019061029b9190610fe2565b610568565b005b6102bc60048036038101906102b79190610fe2565b610576565b6040516102c9919061103d565b60405180910390f35b6102ec60048036038101906102e79190610fe2565b6105ed565b6040516102f9919061103d565b60405180910390f35b61031c60048036038101906103179190611139565b610610565b6040516103299190611067565b60405180910390f35b606060038054610341906111a8565b80601f016020809104026020016040519081016040528092919081815260200182805461036d906111a8565b80156103ba5780601f1061038f576101008083540402835291602001916103ba565b820191906000526020600020905b81548152906001019060200180831161039d57829003601f168201915b5050505050905090565b6000806103cf610697565b90506103dc81858561069f565b600191505092915050565b6000600254905090565b6103fc838383610868565b505050565b60008061040c610697565b9050610419858285610ade565b610424858585610868565b60019150509392505050565b60006012905090565b600080610444610697565b90506104658185856104568589610610565b6104609190611208565b61069f565b600191505092915050565b61047a8282610b6a565b5050565b61048983838361069f565b505050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060600480546104e5906111a8565b80601f0160208091040260200160405190810160405280929190818152602001828054610511906111a8565b801561055e5780601f106105335761010080835404028352916020019161055e565b820191906000526020600020905b81548152906001019060200180831161054157829003601f168201915b5050505050905090565b6105728282610cc0565b5050565b600080610581610697565b9050600061058f8286610610565b9050838110156105d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cb906112ae565b60405180910390fd5b6105e1828686840361069f565b60019250505092915050565b6000806105f8610697565b9050610605818585610868565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361070e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070590611340565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361077d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610774906113d2565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405161085b9190611067565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ce90611464565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610946576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093d906114f6565b60405180910390fd5b610951838383610e8d565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156109d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ce90611588565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ac59190611067565b60405180910390a3610ad8848484610e92565b50505050565b6000610aea8484610610565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610b645781811015610b56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4d906115f4565b60405180910390fd5b610b63848484840361069f565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd090611660565b60405180910390fd5b610be560008383610e8d565b8060026000828254610bf79190611208565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610ca89190611067565b60405180910390a3610cbc60008383610e92565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610d2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d26906116f2565b60405180910390fd5b610d3b82600083610e8d565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015610dc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db890611784565b60405180910390fd5b8181036000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610e749190611067565b60405180910390a3610e8883600084610e92565b505050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ed1578082015181840152602081019050610eb6565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ef982610e97565b610f038185610ea2565b9350610f13818560208601610eb3565b610f1c81610edd565b840191505092915050565b60006020820190508181036000830152610f418184610eee565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610f7982610f4e565b9050919050565b610f8981610f6e565b8114610f9457600080fd5b50565b600081359050610fa681610f80565b92915050565b6000819050919050565b610fbf81610fac565b8114610fca57600080fd5b50565b600081359050610fdc81610fb6565b92915050565b60008060408385031215610ff957610ff8610f49565b5b600061100785828601610f97565b925050602061101885828601610fcd565b9150509250929050565b60008115159050919050565b61103781611022565b82525050565b6000602082019050611052600083018461102e565b92915050565b61106181610fac565b82525050565b600060208201905061107c6000830184611058565b92915050565b60008060006060848603121561109b5761109a610f49565b5b60006110a986828701610f97565b93505060206110ba86828701610f97565b92505060406110cb86828701610fcd565b9150509250925092565b600060ff82169050919050565b6110eb816110d5565b82525050565b600060208201905061110660008301846110e2565b92915050565b60006020828403121561112257611121610f49565b5b600061113084828501610f97565b91505092915050565b600080604083850312156111505761114f610f49565b5b600061115e85828601610f97565b925050602061116f85828601610f97565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806111c057607f821691505b6020821081036111d3576111d2611179565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061121382610fac565b915061121e83610fac565b9250828201905080821115611236576112356111d9565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000611298602583610ea2565b91506112a38261123c565b604082019050919050565b600060208201905081810360008301526112c78161128b565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b600061132a602483610ea2565b9150611335826112ce565b604082019050919050565b600060208201905081810360008301526113598161131d565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b60006113bc602283610ea2565b91506113c782611360565b604082019050919050565b600060208201905081810360008301526113eb816113af565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b600061144e602583610ea2565b9150611459826113f2565b604082019050919050565b6000602082019050818103600083015261147d81611441565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b60006114e0602383610ea2565b91506114eb82611484565b604082019050919050565b6000602082019050818103600083015261150f816114d3565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000611572602683610ea2565b915061157d82611516565b604082019050919050565b600060208201905081810360008301526115a181611565565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b60006115de601d83610ea2565b91506115e9826115a8565b602082019050919050565b6000602082019050818103600083015261160d816115d1565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600061164a601f83610ea2565b915061165582611614565b602082019050919050565b600060208201905081810360008301526116798161163d565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b60006116dc602183610ea2565b91506116e782611680565b604082019050919050565b6000602082019050818103600083015261170b816116cf565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b600061176e602283610ea2565b915061177982611712565b604082019050919050565b6000602082019050818103600083015261179d81611761565b905091905056fea26469706673582212206a0466cc8279c36801cc7618e809890da047e4518cddd96836b2e2250be5535764736f6c63430008100033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000204fce5e3e25020000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x4554480000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x45544820636f696e000000000000000000000000000000000000000000000010", + "0x62a9a27ba8ad7d7d9c6567de722ea497f95a95e67f937096a94d55dbefc0109b": "0x0000000000000000000000000000000000000000204fce5e3e25020000000000" + }, + "balance": "0x0" + }, + "7363726f6c6c6c20000000000000000000000015": { + "code": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806321848c46146100515780632e64cec11461006d578063b0f2b72a1461008b578063f3417673146100a7575b600080fd5b61006b6004803603810190610066919061013c565b6100c5565b005b6100756100da565b6040516100829190610178565b60405180910390f35b6100a560048036038101906100a0919061013c565b6100e3565b005b6100af6100ed565b6040516100bc9190610178565b60405180910390f35b8060008190555060006100d757600080fd5b50565b60008054905090565b8060008190555050565b6000806100f957600080fd5b600054905090565b600080fd5b6000819050919050565b61011981610106565b811461012457600080fd5b50565b60008135905061013681610110565b92915050565b60006020828403121561015257610151610101565b5b600061016084828501610127565b91505092915050565b61017281610106565b82525050565b600060208201905061018d6000830184610169565b9291505056fea2646970667358221220413877599bcbec5f450129f8e1933af2bd0fcc9934b4647a75fe0079cde3c55764736f6c63430008100033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000010000" + }, + "balance": "0x0" } }, "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "baseFeePerGas": "0x2710" -} \ No newline at end of file +} diff --git a/tests/integration-test/contracts_test.go b/tests/integration-test/contracts_test.go new file mode 100644 index 000000000..41204371e --- /dev/null +++ b/tests/integration-test/contracts_test.go @@ -0,0 +1,28 @@ +package integration + +import ( + "testing" + + "github.com/scroll-tech/go-ethereum/common" + "github.com/stretchr/testify/assert" + + "scroll-tech/common/bytecode/erc20" +) + +var ( + erc20Address = common.HexToAddress("0x7363726f6c6c6c20000000000000000000000014") + greeterAddress = common.HexToAddress("0x7363726f6c6c6c20000000000000000000000015") +) + +func TestERC20(t *testing.T) { + // Start l2geth docker. + base.RunL2Geth(t) + + l2Cli, err := base.L2Client() + assert.Nil(t, err) + token, err := erc20.NewERC20Mock(erc20Address, l2Cli) + assert.NoError(t, err) + bls, err := token.BalanceOf(nil, erc20Address) + assert.NoError(t, err) + assert.Equal(t, int64(0), bls.Int64()) +} From cf9f0b921ff96b6590de4b7d743afc7c4fa711d7 Mon Sep 17 00:00:00 2001 From: Xi Lin Date: Fri, 21 Apr 2023 19:27:49 +0800 Subject: [PATCH 2/7] feat(contracts): forward data to receiver after deposit/withdraw (#429) Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- contracts/docs/apis/L2ERC1155Gateway.md | 8 ++++---- contracts/docs/apis/L2ERC721Gateway.md | 8 ++++---- .../src/L1/gateways/L1CustomERC20Gateway.sol | 2 +- contracts/src/L1/gateways/L1ETHGateway.sol | 2 +- .../src/L1/gateways/L1StandardERC20Gateway.sol | 2 +- contracts/src/L1/gateways/L1WETHGateway.sol | 2 +- .../src/L2/gateways/L2CustomERC20Gateway.sol | 4 ++-- contracts/src/L2/gateways/L2ETHGateway.sol | 2 +- .../src/L2/gateways/L2StandardERC20Gateway.sol | 4 ++-- contracts/src/L2/gateways/L2WETHGateway.sol | 2 +- .../{token => callbacks}/IERC677Receiver.sol | 0 .../callbacks/IScrollGatewayCallback.sol | 7 +++++++ .../src/libraries/gateway/ScrollGatewayBase.sol | 14 ++++++++++++++ .../src/libraries/token/ScrollStandardERC20.sol | 2 +- contracts/src/test/L1CustomERC20Gateway.t.sol | 13 ++++++------- contracts/src/test/L1ETHGateway.t.sol | 13 ++++++------- contracts/src/test/L1StandardERC20Gateway.t.sol | 14 ++++++-------- contracts/src/test/L1WETHGateway.t.sol | 13 ++++++------- contracts/src/test/L2CustomERC20Gateway.t.sol | 14 ++++++-------- contracts/src/test/L2ETHGateway.t.sol | 12 ++++++------ contracts/src/test/L2StandardERC20Gateway.t.sol | 14 ++++++-------- contracts/src/test/L2WETHGateway.t.sol | 12 ++++++------ contracts/src/test/mocks/MockGatewayRecipient.sol | 15 +++++++++++++++ 23 files changed, 103 insertions(+), 76 deletions(-) rename contracts/src/libraries/{token => callbacks}/IERC677Receiver.sol (100%) create mode 100644 contracts/src/libraries/callbacks/IScrollGatewayCallback.sol create mode 100644 contracts/src/test/mocks/MockGatewayRecipient.sol diff --git a/contracts/docs/apis/L2ERC1155Gateway.md b/contracts/docs/apis/L2ERC1155Gateway.md index f6071117b..e3c887098 100644 --- a/contracts/docs/apis/L2ERC1155Gateway.md +++ b/contracts/docs/apis/L2ERC1155Gateway.md @@ -13,7 +13,7 @@ The `L2ERC1155Gateway` is used to withdraw ERC1155 compatible NFTs in layer 2 an ### batchWithdrawERC1155 ```solidity -function batchWithdrawERC1155(address _token, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external nonpayable +function batchWithdrawERC1155(address _token, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external payable ``` Batch withdraw a list of ERC1155 NFT to caller's account on layer 1. @@ -32,7 +32,7 @@ Batch withdraw a list of ERC1155 NFT to caller's account on layer 1. ### batchWithdrawERC1155 ```solidity -function batchWithdrawERC1155(address _token, address _to, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external nonpayable +function batchWithdrawERC1155(address _token, address _to, uint256[] _tokenIds, uint256[] _amounts, uint256 _gasLimit) external payable ``` Batch withdraw a list of ERC1155 NFT to caller's account on layer 1. @@ -319,7 +319,7 @@ Update layer 2 to layer 1 token mapping. ### withdrawERC1155 ```solidity -function withdrawERC1155(address _token, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external nonpayable +function withdrawERC1155(address _token, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external payable ``` Withdraw some ERC1155 NFT to caller's account on layer 1. @@ -338,7 +338,7 @@ Withdraw some ERC1155 NFT to caller's account on layer 1. ### withdrawERC1155 ```solidity -function withdrawERC1155(address _token, address _to, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external nonpayable +function withdrawERC1155(address _token, address _to, uint256 _tokenId, uint256 _amount, uint256 _gasLimit) external payable ``` Withdraw some ERC1155 NFT to caller's account on layer 1. diff --git a/contracts/docs/apis/L2ERC721Gateway.md b/contracts/docs/apis/L2ERC721Gateway.md index 87823e0de..103aa7ffb 100644 --- a/contracts/docs/apis/L2ERC721Gateway.md +++ b/contracts/docs/apis/L2ERC721Gateway.md @@ -13,7 +13,7 @@ The `L2ERC721Gateway` is used to withdraw ERC721 compatible NFTs in layer 2 and ### batchWithdrawERC721 ```solidity -function batchWithdrawERC721(address _token, uint256[] _tokenIds, uint256 _gasLimit) external nonpayable +function batchWithdrawERC721(address _token, uint256[] _tokenIds, uint256 _gasLimit) external payable ``` Batch withdraw a list of ERC721 NFT to caller's account on layer 1. @@ -31,7 +31,7 @@ Batch withdraw a list of ERC721 NFT to caller's account on layer 1. ### batchWithdrawERC721 ```solidity -function batchWithdrawERC721(address _token, address _to, uint256[] _tokenIds, uint256 _gasLimit) external nonpayable +function batchWithdrawERC721(address _token, address _to, uint256[] _tokenIds, uint256 _gasLimit) external payable ``` Batch withdraw a list of ERC721 NFT to caller's account on layer 1. @@ -266,7 +266,7 @@ Update layer 2 to layer 1 token mapping. ### withdrawERC721 ```solidity -function withdrawERC721(address _token, uint256 _tokenId, uint256 _gasLimit) external nonpayable +function withdrawERC721(address _token, uint256 _tokenId, uint256 _gasLimit) external payable ``` Withdraw some ERC721 NFT to caller's account on layer 1. @@ -284,7 +284,7 @@ Withdraw some ERC721 NFT to caller's account on layer 1. ### withdrawERC721 ```solidity -function withdrawERC721(address _token, address _to, uint256 _tokenId, uint256 _gasLimit) external nonpayable +function withdrawERC721(address _token, address _to, uint256 _tokenId, uint256 _gasLimit) external payable ``` Withdraw some ERC721 NFT to caller's account on layer 1. diff --git a/contracts/src/L1/gateways/L1CustomERC20Gateway.sol b/contracts/src/L1/gateways/L1CustomERC20Gateway.sol index b43bfae2f..442438fcf 100644 --- a/contracts/src/L1/gateways/L1CustomERC20Gateway.sol +++ b/contracts/src/L1/gateways/L1CustomERC20Gateway.sol @@ -85,7 +85,7 @@ contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20G // but it seems not a big problem. IERC20Upgradeable(_l1Token).safeTransfer(_to, _amount); - // @todo forward `_data` to `_to` in the near future + _doCallback(_to, _data); emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data); } diff --git a/contracts/src/L1/gateways/L1ETHGateway.sol b/contracts/src/L1/gateways/L1ETHGateway.sol index 5e31bed31..4eff4e2b4 100644 --- a/contracts/src/L1/gateways/L1ETHGateway.sol +++ b/contracts/src/L1/gateways/L1ETHGateway.sol @@ -74,7 +74,7 @@ contract L1ETHGateway is Initializable, ScrollGatewayBase, IL1ETHGateway { (bool _success, ) = _to.call{value: _amount}(""); require(_success, "ETH transfer failed"); - // @todo farward _data to `_to` in near future. + _doCallback(_to, _data); emit FinalizeWithdrawETH(_from, _to, _amount, _data); } diff --git a/contracts/src/L1/gateways/L1StandardERC20Gateway.sol b/contracts/src/L1/gateways/L1StandardERC20Gateway.sol index ecb8f41c9..d51323f86 100644 --- a/contracts/src/L1/gateways/L1StandardERC20Gateway.sol +++ b/contracts/src/L1/gateways/L1StandardERC20Gateway.sol @@ -99,7 +99,7 @@ contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gate // but it seems not a big problem. IERC20(_l1Token).safeTransfer(_to, _amount); - // @todo forward `_data` to `_to` in the near future + _doCallback(_to, _data); emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data); } diff --git a/contracts/src/L1/gateways/L1WETHGateway.sol b/contracts/src/L1/gateways/L1WETHGateway.sol index f1e13e01d..f23751d50 100644 --- a/contracts/src/L1/gateways/L1WETHGateway.sol +++ b/contracts/src/L1/gateways/L1WETHGateway.sol @@ -90,7 +90,7 @@ contract L1WETHGateway is Initializable, ScrollGatewayBase, L1ERC20Gateway { IWETH(_l1Token).deposit{value: _amount}(); IERC20(_l1Token).safeTransfer(_to, _amount); - // @todo forward `_data` to `_to`. + _doCallback(_to, _data); emit FinalizeWithdrawERC20(_l1Token, _l2Token, _from, _to, _amount, _data); } diff --git a/contracts/src/L2/gateways/L2CustomERC20Gateway.sol b/contracts/src/L2/gateways/L2CustomERC20Gateway.sol index 05c98475e..233b164e6 100644 --- a/contracts/src/L2/gateways/L2CustomERC20Gateway.sol +++ b/contracts/src/L2/gateways/L2CustomERC20Gateway.sol @@ -79,10 +79,10 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G require(msg.value == 0, "nonzero msg.value"); require(_l1Token == tokenMapping[_l2Token], "l1 token mismatch"); - // @todo forward `_callData` to `_to` using transferAndCall in the near future - IScrollStandardERC20(_l2Token).mint(_to, _amount); + _doCallback(_to, _data); + emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data); } diff --git a/contracts/src/L2/gateways/L2ETHGateway.sol b/contracts/src/L2/gateways/L2ETHGateway.sol index 2a1b394d1..7ca11826d 100644 --- a/contracts/src/L2/gateways/L2ETHGateway.sol +++ b/contracts/src/L2/gateways/L2ETHGateway.sol @@ -72,7 +72,7 @@ contract L2ETHGateway is Initializable, ScrollGatewayBase, IL2ETHGateway { (bool _success, ) = _to.call{value: _amount}(""); require(_success, "ETH transfer failed"); - // @todo farward _data to `_to` in near future. + _doCallback(_to, _data); emit FinalizeDepositETH(_from, _to, _amount, _data); } diff --git a/contracts/src/L2/gateways/L2StandardERC20Gateway.sol b/contracts/src/L2/gateways/L2StandardERC20Gateway.sol index e1cd3bd64..53c732dbf 100644 --- a/contracts/src/L2/gateways/L2StandardERC20Gateway.sol +++ b/contracts/src/L2/gateways/L2StandardERC20Gateway.sol @@ -105,10 +105,10 @@ contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gate _deployL2Token(_deployData, _l1Token); } - // @todo forward `_callData` to `_to` using transferAndCall in the near future - IScrollStandardERC20(_l2Token).mint(_to, _amount); + _doCallback(_to, _callData); + emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _callData); } diff --git a/contracts/src/L2/gateways/L2WETHGateway.sol b/contracts/src/L2/gateways/L2WETHGateway.sol index 741a1cad0..e8d4173a1 100644 --- a/contracts/src/L2/gateways/L2WETHGateway.sol +++ b/contracts/src/L2/gateways/L2WETHGateway.sol @@ -90,7 +90,7 @@ contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway { IWETH(_l2Token).deposit{value: _amount}(); IERC20(_l2Token).safeTransfer(_to, _amount); - // @todo forward `_data` to `_to` in near future + _doCallback(_to, _data); emit FinalizeDepositERC20(_l1Token, _l2Token, _from, _to, _amount, _data); } diff --git a/contracts/src/libraries/token/IERC677Receiver.sol b/contracts/src/libraries/callbacks/IERC677Receiver.sol similarity index 100% rename from contracts/src/libraries/token/IERC677Receiver.sol rename to contracts/src/libraries/callbacks/IERC677Receiver.sol diff --git a/contracts/src/libraries/callbacks/IScrollGatewayCallback.sol b/contracts/src/libraries/callbacks/IScrollGatewayCallback.sol new file mode 100644 index 000000000..fcedd8c16 --- /dev/null +++ b/contracts/src/libraries/callbacks/IScrollGatewayCallback.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IScrollGatewayCallback { + function onScrollGatewayCallback(bytes memory data) external; +} diff --git a/contracts/src/libraries/gateway/ScrollGatewayBase.sol b/contracts/src/libraries/gateway/ScrollGatewayBase.sol index df6e6216b..635aa6191 100644 --- a/contracts/src/libraries/gateway/ScrollGatewayBase.sol +++ b/contracts/src/libraries/gateway/ScrollGatewayBase.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import {IScrollGateway} from "./IScrollGateway.sol"; import {IScrollMessenger} from "../IScrollMessenger.sol"; +import {IScrollGatewayCallback} from "../callbacks/IScrollGatewayCallback.sol"; abstract contract ScrollGatewayBase is IScrollGateway { /************* @@ -83,4 +84,17 @@ abstract contract ScrollGatewayBase is IScrollGateway { // for reentrancy guard _status = _NOT_ENTERED; } + + /********************** + * Internal Functions * + **********************/ + + /// @dev Internal function to forward calldata to target contract. + /// @param _to The address of contract to call. + /// @param _data The calldata passed to the contract. + function _doCallback(address _to, bytes memory _data) internal { + if (_data.length > 0 && _to.code.length > 0) { + IScrollGatewayCallback(_to).onScrollGatewayCallback(_data); + } + } } diff --git a/contracts/src/libraries/token/ScrollStandardERC20.sol b/contracts/src/libraries/token/ScrollStandardERC20.sol index 9f65c6da9..1d47145f8 100644 --- a/contracts/src/libraries/token/ScrollStandardERC20.sol +++ b/contracts/src/libraries/token/ScrollStandardERC20.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; import {IScrollStandardERC20} from "./IScrollStandardERC20.sol"; -import {IERC677Receiver} from "./IERC677Receiver.sol"; +import {IERC677Receiver} from "../callbacks/IERC677Receiver.sol"; contract ScrollStandardERC20 is ERC20PermitUpgradeable, IScrollStandardERC20 { /// @inheritdoc IScrollStandardERC20 diff --git a/contracts/src/test/L1CustomERC20Gateway.t.sol b/contracts/src/test/L1CustomERC20Gateway.t.sol index f99019d46..63f96a5a4 100644 --- a/contracts/src/test/L1CustomERC20Gateway.t.sol +++ b/contracts/src/test/L1CustomERC20Gateway.t.sol @@ -12,6 +12,7 @@ import {AddressAliasHelper} from "../libraries/common/AddressAliasHelper.sol"; import {L1GatewayTestBase} from "./L1GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L1CustomERC20GatewayTest is L1GatewayTestBase { // from L1CustomERC20Gateway @@ -250,12 +251,10 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase { function testFinalizeWithdrawERC20( address sender, - address recipient, uint256 amount, bytes memory dataToCall ) public { - // blacklist some addresses - hevm.assume(recipient != address(0)); + MockGatewayRecipient recipient = new MockGatewayRecipient(); gateway.updateTokenMapping(address(l1Token), address(l2Token)); @@ -270,7 +269,7 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase { address(l1Token), address(l2Token), sender, - recipient, + address(recipient), amount, dataToCall ); @@ -291,7 +290,7 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase { // emit FinalizeWithdrawERC20 from L1StandardERC20Gateway { hevm.expectEmit(true, true, true, true); - emit FinalizeWithdrawERC20(address(l1Token), address(l2Token), sender, recipient, amount, dataToCall); + emit FinalizeWithdrawERC20(address(l1Token), address(l2Token), sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L1ScrollMessenger @@ -301,11 +300,11 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase { } uint256 gatewayBalance = l1Token.balanceOf(address(gateway)); - uint256 recipientBalance = l1Token.balanceOf(recipient); + uint256 recipientBalance = l1Token.balanceOf(address(recipient)); assertBoolEq(false, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); l1Messenger.relayMessageWithProof(address(counterpartGateway), address(gateway), 0, 0, message, proof); assertEq(gatewayBalance - amount, l1Token.balanceOf(address(gateway))); - assertEq(recipientBalance + amount, l1Token.balanceOf(recipient)); + assertEq(recipientBalance + amount, l1Token.balanceOf(address(recipient))); assertBoolEq(true, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L1ETHGateway.t.sol b/contracts/src/test/L1ETHGateway.t.sol index 3b9b1b9d8..3350c1b8d 100644 --- a/contracts/src/test/L1ETHGateway.t.sol +++ b/contracts/src/test/L1ETHGateway.t.sol @@ -10,6 +10,7 @@ import {AddressAliasHelper} from "../libraries/common/AddressAliasHelper.sol"; import {L1GatewayTestBase} from "./L1GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L1ETHGatewayTest is L1GatewayTestBase { // from L1ETHGateway @@ -188,12 +189,10 @@ contract L1ETHGatewayTest is L1GatewayTestBase { function testFinalizeWithdrawETH( address sender, - address recipient, uint256 amount, bytes memory dataToCall ) public { - hevm.assume(recipient.code.length == 0); - hevm.assume(uint256(uint160(recipient)) > 100); // ignore some precompile contracts + MockGatewayRecipient recipient = new MockGatewayRecipient(); amount = bound(amount, 1, address(this).balance / 2); @@ -204,7 +203,7 @@ contract L1ETHGatewayTest is L1GatewayTestBase { bytes memory message = abi.encodeWithSelector( IL1ETHGateway.finalizeWithdrawETH.selector, sender, - recipient, + address(recipient), amount, dataToCall ); @@ -225,7 +224,7 @@ contract L1ETHGatewayTest is L1GatewayTestBase { // emit FinalizeWithdrawETH from L1ETHGateway { hevm.expectEmit(true, true, false, true); - emit FinalizeWithdrawETH(sender, recipient, amount, dataToCall); + emit FinalizeWithdrawETH(sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L1ScrollMessenger @@ -235,11 +234,11 @@ contract L1ETHGatewayTest is L1GatewayTestBase { } uint256 messengerBalance = address(l1Messenger).balance; - uint256 recipientBalance = recipient.balance; + uint256 recipientBalance = address(recipient).balance; assertBoolEq(false, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); l1Messenger.relayMessageWithProof(address(counterpartGateway), address(gateway), amount, 0, message, proof); assertEq(messengerBalance - amount, address(l1Messenger).balance); - assertEq(recipientBalance + amount, recipient.balance); + assertEq(recipientBalance + amount, address(recipient).balance); assertBoolEq(true, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L1StandardERC20Gateway.t.sol b/contracts/src/test/L1StandardERC20Gateway.t.sol index a1cdf060f..7e61afee4 100644 --- a/contracts/src/test/L1StandardERC20Gateway.t.sol +++ b/contracts/src/test/L1StandardERC20Gateway.t.sol @@ -16,6 +16,7 @@ import {L1GatewayTestBase} from "./L1GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; import {TransferReentrantToken} from "./mocks/tokens/TransferReentrantToken.sol"; import {FeeOnTransferToken} from "./mocks/tokens/FeeOnTransferToken.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L1StandardERC20GatewayTest is L1GatewayTestBase { // from L1StandardERC20Gateway @@ -326,13 +327,10 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase { function testFinalizeWithdrawERC20( address sender, - address recipient, uint256 amount, bytes memory dataToCall ) public { - // blacklist some addresses - hevm.assume(recipient != address(0)); - hevm.assume(recipient != address(gateway)); + MockGatewayRecipient recipient = new MockGatewayRecipient(); amount = bound(amount, 1, l1Token.balanceOf(address(this))); @@ -345,7 +343,7 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase { address(l1Token), address(l2Token), sender, - recipient, + address(recipient), amount, dataToCall ); @@ -366,7 +364,7 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase { // emit FinalizeWithdrawERC20 from L1StandardERC20Gateway { hevm.expectEmit(true, true, true, true); - emit FinalizeWithdrawERC20(address(l1Token), address(l2Token), sender, recipient, amount, dataToCall); + emit FinalizeWithdrawERC20(address(l1Token), address(l2Token), sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L1ScrollMessenger @@ -376,11 +374,11 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase { } uint256 gatewayBalance = l1Token.balanceOf(address(gateway)); - uint256 recipientBalance = l1Token.balanceOf(recipient); + uint256 recipientBalance = l1Token.balanceOf(address(recipient)); assertBoolEq(false, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); l1Messenger.relayMessageWithProof(address(counterpartGateway), address(gateway), 0, 0, message, proof); assertEq(gatewayBalance - amount, l1Token.balanceOf(address(gateway))); - assertEq(recipientBalance + amount, l1Token.balanceOf(recipient)); + assertEq(recipientBalance + amount, l1Token.balanceOf(address(recipient))); assertBoolEq(true, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L1WETHGateway.t.sol b/contracts/src/test/L1WETHGateway.t.sol index c13aebdf2..7986dfc72 100644 --- a/contracts/src/test/L1WETHGateway.t.sol +++ b/contracts/src/test/L1WETHGateway.t.sol @@ -12,6 +12,7 @@ import {AddressAliasHelper} from "../libraries/common/AddressAliasHelper.sol"; import {L1GatewayTestBase} from "./L1GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L1WETHGatewayTest is L1GatewayTestBase { // from L1WETHGateway @@ -278,12 +279,10 @@ contract L1WETHGatewayTest is L1GatewayTestBase { function testFinalizeWithdrawERC20( address sender, - address recipient, uint256 amount, bytes memory dataToCall ) public { - // blacklist some addresses - hevm.assume(recipient != address(0)); + MockGatewayRecipient recipient = new MockGatewayRecipient(); amount = bound(amount, 1, l1weth.balanceOf(address(this))); @@ -296,7 +295,7 @@ contract L1WETHGatewayTest is L1GatewayTestBase { address(l1weth), address(l2weth), sender, - recipient, + address(recipient), amount, dataToCall ); @@ -317,7 +316,7 @@ contract L1WETHGatewayTest is L1GatewayTestBase { // emit FinalizeWithdrawERC20 from L1WETHGateway { hevm.expectEmit(true, true, true, true); - emit FinalizeWithdrawERC20(address(l1weth), address(l2weth), sender, recipient, amount, dataToCall); + emit FinalizeWithdrawERC20(address(l1weth), address(l2weth), sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L1ScrollMessenger @@ -327,11 +326,11 @@ contract L1WETHGatewayTest is L1GatewayTestBase { } uint256 messengerBalance = address(l1Messenger).balance; - uint256 recipientBalance = l1weth.balanceOf(recipient); + uint256 recipientBalance = l1weth.balanceOf(address(recipient)); assertBoolEq(false, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); l1Messenger.relayMessageWithProof(address(counterpartGateway), address(gateway), amount, 0, message, proof); assertEq(messengerBalance - amount, address(l1Messenger).balance); - assertEq(recipientBalance + amount, l1weth.balanceOf(recipient)); + assertEq(recipientBalance + amount, l1weth.balanceOf(address(recipient))); assertBoolEq(true, l1Messenger.isL2MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L2CustomERC20Gateway.t.sol b/contracts/src/test/L2CustomERC20Gateway.t.sol index 79b7a2205..57bdf47df 100644 --- a/contracts/src/test/L2CustomERC20Gateway.t.sol +++ b/contracts/src/test/L2CustomERC20Gateway.t.sol @@ -10,6 +10,7 @@ import {L2GatewayRouter} from "../L2/gateways/L2GatewayRouter.sol"; import {L2GatewayTestBase} from "./L2GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L2CustomERC20GatewayTest is L2GatewayTestBase { // from L1CustomERC20Gateway @@ -231,13 +232,10 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase { function testFinalizeDepositERC20( address sender, - address recipient, uint256 amount, bytes memory dataToCall ) public { - // blacklist some addresses - hevm.assume(recipient != address(0)); - hevm.assume(recipient != address(gateway)); + MockGatewayRecipient recipient = new MockGatewayRecipient(); gateway.updateTokenMapping(address(l2Token), address(l1Token)); @@ -249,7 +247,7 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase { address(l1Token), address(l2Token), sender, - recipient, + address(recipient), amount, dataToCall ); @@ -265,7 +263,7 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase { // emit FinalizeDepositERC20 from L2CustomERC20Gateway { hevm.expectEmit(true, true, true, true); - emit FinalizeDepositERC20(address(l1Token), address(l2Token), sender, recipient, amount, dataToCall); + emit FinalizeDepositERC20(address(l1Token), address(l2Token), sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L2ScrollMessenger @@ -275,11 +273,11 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase { } uint256 gatewayBalance = l2Token.balanceOf(address(gateway)); - uint256 recipientBalance = l2Token.balanceOf(recipient); + uint256 recipientBalance = l2Token.balanceOf(address(recipient)); assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); l2Messenger.relayMessage(address(counterpartGateway), address(gateway), 0, 0, message); assertEq(gatewayBalance, l2Token.balanceOf(address(gateway))); - assertEq(recipientBalance + amount, l2Token.balanceOf(recipient)); + assertEq(recipientBalance + amount, l2Token.balanceOf(address(recipient))); assertBoolEq(true, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L2ETHGateway.t.sol b/contracts/src/test/L2ETHGateway.t.sol index 8e7265f8d..c31ab3bc9 100644 --- a/contracts/src/test/L2ETHGateway.t.sol +++ b/contracts/src/test/L2ETHGateway.t.sol @@ -8,6 +8,7 @@ import {IL2ETHGateway, L2ETHGateway} from "../L2/gateways/L2ETHGateway.sol"; import {L2GatewayTestBase} from "./L2GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L2ETHGatewayTest is L2GatewayTestBase { // from L2ETHGateway @@ -184,8 +185,7 @@ contract L2ETHGatewayTest is L2GatewayTestBase { uint256 amount, bytes memory dataToCall ) public { - hevm.assume(recipient.code.length == 0); - hevm.assume(uint256(uint160(recipient)) > 100); // ignore some precompile contracts + MockGatewayRecipient recipient = new MockGatewayRecipient(); amount = bound(amount, 1, address(this).balance / 2); @@ -196,7 +196,7 @@ contract L2ETHGatewayTest is L2GatewayTestBase { bytes memory message = abi.encodeWithSelector( IL2ETHGateway.finalizeDepositETH.selector, sender, - recipient, + address(recipient), amount, dataToCall ); @@ -212,7 +212,7 @@ contract L2ETHGatewayTest is L2GatewayTestBase { // emit FinalizeDepositETH from L2ETHGateway { hevm.expectEmit(true, true, false, true); - emit FinalizeDepositETH(sender, recipient, amount, dataToCall); + emit FinalizeDepositETH(sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L2ScrollMessenger @@ -222,11 +222,11 @@ contract L2ETHGatewayTest is L2GatewayTestBase { } uint256 messengerBalance = address(l2Messenger).balance; - uint256 recipientBalance = recipient.balance; + uint256 recipientBalance = address(recipient).balance; assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); l2Messenger.relayMessage(address(counterpartGateway), address(gateway), amount, 0, message); assertEq(messengerBalance - amount, address(l2Messenger).balance); - assertEq(recipientBalance + amount, recipient.balance); + assertEq(recipientBalance + amount, address(recipient).balance); assertBoolEq(true, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L2StandardERC20Gateway.t.sol b/contracts/src/test/L2StandardERC20Gateway.t.sol index 56cab0629..e91ae9661 100644 --- a/contracts/src/test/L2StandardERC20Gateway.t.sol +++ b/contracts/src/test/L2StandardERC20Gateway.t.sol @@ -12,6 +12,7 @@ import {ScrollStandardERC20Factory} from "../libraries/token/ScrollStandardERC20 import {L2GatewayTestBase} from "./L2GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L2StandardERC20GatewayTest is L2GatewayTestBase { // from L2StandardERC20Gateway @@ -263,13 +264,10 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase { function testFinalizeDepositERC20( address sender, - address recipient, uint256 amount, bytes memory dataToCall ) public { - // blacklist some addresses - hevm.assume(recipient != address(0)); - hevm.assume(recipient != address(gateway)); + MockGatewayRecipient recipient = new MockGatewayRecipient(); amount = bound(amount, 1, l2Token.balanceOf(address(this))); @@ -279,7 +277,7 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase { address(l1Token), address(l2Token), sender, - recipient, + address(recipient), amount, dataToCall ); @@ -295,7 +293,7 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase { // emit FinalizeDepositERC20 from L2StandardERC20Gateway { hevm.expectEmit(true, true, true, true); - emit FinalizeDepositERC20(address(l1Token), address(l2Token), sender, recipient, amount, dataToCall); + emit FinalizeDepositERC20(address(l1Token), address(l2Token), sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L2ScrollMessenger @@ -305,11 +303,11 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase { } uint256 gatewayBalance = l2Token.balanceOf(address(gateway)); - uint256 recipientBalance = l2Token.balanceOf(recipient); + uint256 recipientBalance = l2Token.balanceOf(address(recipient)); assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); l2Messenger.relayMessage(address(counterpartGateway), address(gateway), 0, 0, message); assertEq(gatewayBalance, l2Token.balanceOf(address(gateway))); - assertEq(recipientBalance + amount, l2Token.balanceOf(recipient)); + assertEq(recipientBalance + amount, l2Token.balanceOf(address(recipient))); assertBoolEq(true, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/L2WETHGateway.t.sol b/contracts/src/test/L2WETHGateway.t.sol index 25025747e..eeb1362b2 100644 --- a/contracts/src/test/L2WETHGateway.t.sol +++ b/contracts/src/test/L2WETHGateway.t.sol @@ -10,6 +10,7 @@ import {IL2ERC20Gateway, L2WETHGateway} from "../L2/gateways/L2WETHGateway.sol"; import {L2GatewayTestBase} from "./L2GatewayTestBase.t.sol"; import {MockScrollMessenger} from "./mocks/MockScrollMessenger.sol"; +import {MockGatewayRecipient} from "./mocks/MockGatewayRecipient.sol"; contract L2WETHGatewayTest is L2GatewayTestBase { // from L2WETHGateway @@ -275,8 +276,7 @@ contract L2WETHGatewayTest is L2GatewayTestBase { uint256 amount, bytes memory dataToCall ) public { - // blacklist some addresses - hevm.assume(recipient != address(0)); + MockGatewayRecipient recipient = new MockGatewayRecipient(); amount = bound(amount, 1, l2weth.balanceOf(address(this))); @@ -289,7 +289,7 @@ contract L2WETHGatewayTest is L2GatewayTestBase { address(l1weth), address(l2weth), sender, - recipient, + address(recipient), amount, dataToCall ); @@ -305,7 +305,7 @@ contract L2WETHGatewayTest is L2GatewayTestBase { // emit FinalizeDepositERC20 from L2WETHGateway { hevm.expectEmit(true, true, true, true); - emit FinalizeDepositERC20(address(l1weth), address(l2weth), sender, recipient, amount, dataToCall); + emit FinalizeDepositERC20(address(l1weth), address(l2weth), sender, address(recipient), amount, dataToCall); } // emit RelayedMessage from L2ScrollMessenger @@ -315,11 +315,11 @@ contract L2WETHGatewayTest is L2GatewayTestBase { } uint256 messengerBalance = address(l2Messenger).balance; - uint256 recipientBalance = l2weth.balanceOf(recipient); + uint256 recipientBalance = l2weth.balanceOf(address(recipient)); assertBoolEq(false, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); l2Messenger.relayMessage(address(counterpartGateway), address(gateway), amount, 0, message); assertEq(messengerBalance - amount, address(l2Messenger).balance); - assertEq(recipientBalance + amount, l2weth.balanceOf(recipient)); + assertEq(recipientBalance + amount, l2weth.balanceOf(address(recipient))); assertBoolEq(true, l2Messenger.isL1MessageExecuted(keccak256(xDomainCalldata))); } diff --git a/contracts/src/test/mocks/MockGatewayRecipient.sol b/contracts/src/test/mocks/MockGatewayRecipient.sol new file mode 100644 index 000000000..c60e915aa --- /dev/null +++ b/contracts/src/test/mocks/MockGatewayRecipient.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import {IScrollGatewayCallback} from "../../libraries/callbacks/IScrollGatewayCallback.sol"; + +contract MockGatewayRecipient is IScrollGatewayCallback { + event ReceiveCall(bytes data); + + function onScrollGatewayCallback(bytes memory data) external { + emit ReceiveCall(data); + } + + receive() external payable {} +} From 905961d0ad2059dfc92dc80c9342a61a9d0a9147 Mon Sep 17 00:00:00 2001 From: colin <102356659+colinlyguo@users.noreply.github.com> Date: Fri, 21 Apr 2023 20:50:36 +0800 Subject: [PATCH 3/7] fix(Jenkinsfile): specify -coverpkg in unit tests (#431) --- Jenkinsfile | 4 ++-- build/run_tests.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100755 build/run_tests.sh diff --git a/Jenkinsfile b/Jenkinsfile index 78ea3a35a..ced4d3a2c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -59,12 +59,12 @@ pipeline { } stage('Race test bridge package') { steps { - sh 'go test -v -race -coverprofile=coverage.bridge.txt -covermode=atomic scroll-tech/bridge/...' + sh "cd ./bridge && ../build/run_tests.sh bridge" } } stage('Race test coordinator package') { steps { - sh 'go test -v -race -coverprofile=coverage.coordinator.txt -covermode=atomic scroll-tech/coordinator/...' + sh "cd ./coordinator && ../build/run_tests.sh coordinator" } } stage('Race test database package') { diff --git a/build/run_tests.sh b/build/run_tests.sh new file mode 100755 index 000000000..51b8bd52a --- /dev/null +++ b/build/run_tests.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -uex + +profile_name=$1 + +exclude_dirs=("scroll-tech/bridge/cmd" "scroll-tech/bridge/tests" "scroll-tech/bridge/mock_bridge" "scroll-tech/coordinator/cmd") + +all_packages=$(go list ./... | grep -v "^scroll-tech/${profile_name}$") +coverpkg="" + +for pkg in $all_packages; do + exclude_pkg=false + for exclude_dir in "${exclude_dirs[@]}"; do + if [[ $pkg == $exclude_dir* ]]; then + exclude_pkg=true + break + fi + done + + if [ "$exclude_pkg" = false ]; then + if [ -z "$coverpkg" ]; then + coverpkg="$pkg/..." + else + coverpkg="$coverpkg,$pkg/..." + fi + fi +done + +echo "coverage.${profile_name}.txt" +go test -v -race -coverpkg="$coverpkg" -coverprofile=../coverage.${profile_name}.txt -covermode=atomic ./... From ab1cda6568f091ba6f933eccec784c59cbd2395f Mon Sep 17 00:00:00 2001 From: maskpp Date: Sun, 23 Apr 2023 17:15:28 +0800 Subject: [PATCH 4/7] test(coordinator): simplify coordinator tests (#434) --- coordinator/manager_test.go | 72 +++++++++++++++---------------------- 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/coordinator/manager_test.go b/coordinator/manager_test.go index 11d21aaac..5c5ce110b 100644 --- a/coordinator/manager_test.go +++ b/coordinator/manager_test.go @@ -26,39 +26,32 @@ import ( "scroll-tech/coordinator" client2 "scroll-tech/coordinator/client" + coordinator_config "scroll-tech/coordinator/config" "scroll-tech/common/docker" "scroll-tech/common/message" "scroll-tech/common/types" "scroll-tech/common/utils" - - bridge_config "scroll-tech/bridge/config" - - coordinator_config "scroll-tech/coordinator/config" ) var ( - cfg *bridge_config.Config - base *docker.App - + base *docker.App batchData *types.BatchData ) +func TestMain(m *testing.M) { + base = docker.NewDockerApp() + m.Run() + base.Free() +} + func randomURL() string { id, _ := rand.Int(rand.Reader, big.NewInt(2000-1)) return fmt.Sprintf("localhost:%d", 10000+2000+id.Int64()) } func setEnv(t *testing.T) (err error) { - // Start postgres and l2geth docker containers. base.RunDBImage(t) - base.RunL2Geth(t) - - // Load config. - cfg, err = bridge_config.NewConfig("../bridge/config.json") - assert.NoError(t, err) - cfg.DBConfig = base.DBConfig - templateBlockTrace, err := os.ReadFile("../common/testdata/blockTrace_02.json") if err != nil { return err @@ -101,15 +94,12 @@ func TestApis(t *testing.T) { } func testHandshake(t *testing.T) { - // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) - assert.NoError(t, err) - assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) - defer l2db.Close() + // Reset db. + assert.NoError(t, migrate.ResetDB(base.DBClient(t))) // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -122,15 +112,12 @@ func testHandshake(t *testing.T) { } func testFailedHandshake(t *testing.T) { - // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) - assert.NoError(t, err) - assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) - defer l2db.Close() + // Reset db. + assert.NoError(t, migrate.ResetDB(base.DBClient(t))) // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -188,15 +175,12 @@ func testFailedHandshake(t *testing.T) { } func testSeveralConnections(t *testing.T) { - // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) - assert.NoError(t, err) - assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) - defer l2db.Close() + // Reset db. + assert.NoError(t, migrate.ResetDB(base.DBClient(t))) // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -243,14 +227,14 @@ func testSeveralConnections(t *testing.T) { func testValidProof(t *testing.T) { // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) + l2db, err := database.NewOrmFactory(base.DBConfig) assert.NoError(t, err) assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) defer l2db.Close() // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 3, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 3, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -302,14 +286,14 @@ func testValidProof(t *testing.T) { func testInvalidProof(t *testing.T) { // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) + l2db, err := database.NewOrmFactory(base.DBConfig) assert.NoError(t, err) assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) defer l2db.Close() // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 3, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 3, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -360,14 +344,14 @@ func testInvalidProof(t *testing.T) { func testTimedoutProof(t *testing.T) { // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) + l2db, err := database.NewOrmFactory(base.DBConfig) assert.NoError(t, err) assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) defer l2db.Close() // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -440,14 +424,14 @@ func testTimedoutProof(t *testing.T) { func testIdleRollerSelection(t *testing.T) { // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) + l2db, err := database.NewOrmFactory(base.DBConfig) assert.NoError(t, err) assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) defer l2db.Close() // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) defer func() { handler.Shutdown(context.Background()) rollerManager.Stop() @@ -499,7 +483,7 @@ func testIdleRollerSelection(t *testing.T) { func testGracefulRestart(t *testing.T) { // Create db handler and reset db. - l2db, err := database.NewOrmFactory(cfg.DBConfig) + l2db, err := database.NewOrmFactory(base.DBConfig) assert.NoError(t, err) assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) defer l2db.Close() @@ -515,7 +499,7 @@ func testGracefulRestart(t *testing.T) { // Setup coordinator and ws server. wsURL := "ws://" + randomURL() - rollerManager, handler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) // create mock roller roller := newMockRoller(t, "roller_test", wsURL) @@ -532,7 +516,7 @@ func testGracefulRestart(t *testing.T) { rollerManager.Stop() // Setup new coordinator and ws server. - newRollerManager, newHandler := setupCoordinator(t, cfg.DBConfig, 1, wsURL) + newRollerManager, newHandler := setupCoordinator(t, base.DBConfig, 1, wsURL) defer func() { newHandler.Shutdown(context.Background()) newRollerManager.Stop() From 2fafb64e0a2e3bad2ba6ec3efd699c184a10165e Mon Sep 17 00:00:00 2001 From: maskpp Date: Sun, 23 Apr 2023 19:55:22 +0800 Subject: [PATCH 5/7] test(integration): add predeployed erc20 & greeter contract tests (#428) Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- tests/integration-test/contracts_test.go | 56 ++++++++++++++++++++-- tests/integration-test/integration_test.go | 2 +- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/tests/integration-test/contracts_test.go b/tests/integration-test/contracts_test.go index 41204371e..d1ba0d85f 100644 --- a/tests/integration-test/contracts_test.go +++ b/tests/integration-test/contracts_test.go @@ -1,12 +1,16 @@ -package integration +package integration_test import ( + "context" + "math/big" "testing" + "github.com/scroll-tech/go-ethereum/accounts/abi/bind" "github.com/scroll-tech/go-ethereum/common" "github.com/stretchr/testify/assert" "scroll-tech/common/bytecode/erc20" + "scroll-tech/common/bytecode/greeter" ) var ( @@ -15,14 +19,56 @@ var ( ) func TestERC20(t *testing.T) { - // Start l2geth docker. base.RunL2Geth(t) - l2Cli, err := base.L2Client() assert.Nil(t, err) + token, err := erc20.NewERC20Mock(erc20Address, l2Cli) assert.NoError(t, err) - bls, err := token.BalanceOf(nil, erc20Address) + + auth, err := bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKeys[0], base.L2gethImg.ChainID()) assert.NoError(t, err) - assert.Equal(t, int64(0), bls.Int64()) + + authBls0, err := token.BalanceOf(nil, auth.From) + assert.NoError(t, err) + + tokenBls0, err := token.BalanceOf(nil, erc20Address) + assert.NoError(t, err) + + // create tx to transfer balance. + value := big.NewInt(1000) + tx, err := token.Transfer(auth, erc20Address, value) + assert.NoError(t, err) + bind.WaitMined(context.Background(), l2Cli, tx) + + authBls1, err := token.BalanceOf(nil, auth.From) + assert.NoError(t, err) + + tokenBls1, err := token.BalanceOf(nil, erc20Address) + assert.NoError(t, err) + + // check balance. + assert.Equal(t, authBls0.Int64(), authBls1.Add(authBls1, value).Int64()) + assert.Equal(t, tokenBls1.Int64(), tokenBls0.Add(tokenBls0, value).Int64()) +} + +func TestGreeter(t *testing.T) { + base.RunL2Geth(t) + l2Cli, err := base.L2Client() + assert.Nil(t, err) + + auth, err := bind.NewKeyedTransactorWithChainID(bridgeApp.Config.L2Config.RelayerConfig.MessageSenderPrivateKeys[0], base.L2gethImg.ChainID()) + assert.NoError(t, err) + + token, err := greeter.NewGreeter(greeterAddress, l2Cli) + assert.NoError(t, err) + + val := big.NewInt(100) + tx, err := token.SetValue(auth, val) + assert.NoError(t, err) + _, err = bind.WaitMined(context.Background(), l2Cli, tx) + + res, err := token.Retrieve(nil) + assert.NoError(t, err) + assert.Equal(t, val.String(), res.String()) } diff --git a/tests/integration-test/integration_test.go b/tests/integration-test/integration_test.go index 438e92f48..e0114bb24 100644 --- a/tests/integration-test/integration_test.go +++ b/tests/integration-test/integration_test.go @@ -1,4 +1,4 @@ -package integration +package integration_test import ( "crypto/rand" From 10ac638a51e24db9787cfe61e3816b9927444780 Mon Sep 17 00:00:00 2001 From: colin <102356659+colinlyguo@users.noreply.github.com> Date: Sun, 23 Apr 2023 22:28:03 +0800 Subject: [PATCH 6/7] test(coordinator): add more unit tests (#430) Co-authored-by: maskpp --- build/run_tests.sh | 10 +-- coordinator/manager.go | 17 ---- coordinator/manager_test.go | 147 ++++++++++++++++++++++++++++--- coordinator/verifier/mock.go | 5 ++ coordinator/verifier/verifier.go | 7 +- 5 files changed, 149 insertions(+), 37 deletions(-) diff --git a/build/run_tests.sh b/build/run_tests.sh index 51b8bd52a..a5200af49 100755 --- a/build/run_tests.sh +++ b/build/run_tests.sh @@ -3,10 +3,10 @@ set -uex profile_name=$1 -exclude_dirs=("scroll-tech/bridge/cmd" "scroll-tech/bridge/tests" "scroll-tech/bridge/mock_bridge" "scroll-tech/coordinator/cmd") +exclude_dirs=("scroll-tech/bridge/cmd" "scroll-tech/bridge/tests" "scroll-tech/bridge/mock_bridge" "scroll-tech/coordinator/cmd" "scroll-tech/coordinator/config") all_packages=$(go list ./... | grep -v "^scroll-tech/${profile_name}$") -coverpkg="" +coverpkg="scroll-tech/${profile_name}" for pkg in $all_packages; do exclude_pkg=false @@ -18,11 +18,7 @@ for pkg in $all_packages; do done if [ "$exclude_pkg" = false ]; then - if [ -z "$coverpkg" ]; then - coverpkg="$pkg/..." - else - coverpkg="$coverpkg,$pkg/..." - fi + coverpkg="$coverpkg,$pkg/..." fi done diff --git a/coordinator/manager.go b/coordinator/manager.go index e0e68e2b4..a7ae9502a 100644 --- a/coordinator/manager.go +++ b/coordinator/manager.go @@ -595,23 +595,6 @@ func (m *Manager) StartProofGenerationSession(task *types.BlockBatch, prevSessio return true } -// IsRollerIdle determines whether this roller is idle. -func (m *Manager) IsRollerIdle(hexPk string) bool { - m.mu.RLock() - defer m.mu.RUnlock() - // We need to iterate over all sessions because finished sessions will be deleted until the - // timeout. So a busy roller could be marked as idle in a finished session. - for _, sess := range m.sessions { - for pk, roller := range sess.info.Rollers { - if pk == hexPk && roller.Status == types.RollerAssigned { - return false - } - } - } - - return true -} - func (m *Manager) addFailedSession(sess *session, errMsg string) { m.mu.Lock() defer m.mu.Unlock() diff --git a/coordinator/manager_test.go b/coordinator/manager_test.go index 5c5ce110b..8e925ff80 100644 --- a/coordinator/manager_test.go +++ b/coordinator/manager_test.go @@ -10,6 +10,8 @@ import ( "math/big" "net/http" "os" + "reflect" + "sort" "strconv" "strings" "sync" @@ -27,6 +29,7 @@ import ( "scroll-tech/coordinator" client2 "scroll-tech/coordinator/client" coordinator_config "scroll-tech/coordinator/config" + "scroll-tech/coordinator/verifier" "scroll-tech/common/docker" "scroll-tech/common/message" @@ -81,11 +84,11 @@ func TestApis(t *testing.T) { t.Run("TestSeveralConnections", testSeveralConnections) t.Run("TestValidProof", testValidProof) t.Run("TestInvalidProof", testInvalidProof) + t.Run("TestProofGeneratedFailed", testProofGeneratedFailed) t.Run("TestTimedoutProof", testTimedoutProof) t.Run("TestIdleRollerSelection", testIdleRollerSelection) - // TODO: Restart roller alone when received task, can add this test case in integration-test. - //t.Run("TestRollerReconnect", testRollerReconnect) t.Run("TestGracefulRestart", testGracefulRestart) + t.Run("TestListRollers", testListRollers) // Teardown t.Cleanup(func() { @@ -245,7 +248,11 @@ func testValidProof(t *testing.T) { for i := 0; i < len(rollers); i++ { rollers[i] = newMockRoller(t, "roller_test"+strconv.Itoa(i), wsURL) // only roller 0 submits valid proof. - rollers[i].waitTaskAndSendProof(t, time.Second, false, i == 0) + proofStatus := verifiedSuccess + if i > 0 { + proofStatus = generatedFailed + } + rollers[i].waitTaskAndSendProof(t, time.Second, false, proofStatus) } defer func() { // close connection @@ -303,7 +310,65 @@ func testInvalidProof(t *testing.T) { rollers := make([]*mockRoller, 3) for i := 0; i < len(rollers); i++ { rollers[i] = newMockRoller(t, "roller_test"+strconv.Itoa(i), wsURL) - rollers[i].waitTaskAndSendProof(t, time.Second, false, false) + rollers[i].waitTaskAndSendProof(t, time.Second, false, verifiedFailed) + } + defer func() { + // close connection + for _, roller := range rollers { + roller.close() + } + }() + assert.Equal(t, 3, rollerManager.GetNumberOfIdleRollers()) + + var hashes = make([]string, 1) + dbTx, err := l2db.Beginx() + assert.NoError(t, err) + for i := range hashes { + assert.NoError(t, l2db.NewBatchInDBTx(dbTx, batchData)) + hashes[i] = batchData.Hash().Hex() + } + assert.NoError(t, dbTx.Commit()) + + // verify proof status + var ( + tick = time.Tick(500 * time.Millisecond) + tickStop = time.Tick(10 * time.Second) + ) + for len(hashes) > 0 { + select { + case <-tick: + status, err := l2db.GetProvingStatusByHash(hashes[0]) + assert.NoError(t, err) + if status == types.ProvingTaskFailed { + hashes = hashes[1:] + } + case <-tickStop: + t.Error("failed to check proof status") + return + } + } +} + +func testProofGeneratedFailed(t *testing.T) { + // Create db handler and reset db. + l2db, err := database.NewOrmFactory(base.DBConfig) + assert.NoError(t, err) + assert.NoError(t, migrate.ResetDB(l2db.GetDB().DB)) + defer l2db.Close() + + // Setup coordinator and ws server. + wsURL := "ws://" + randomURL() + rollerManager, handler := setupCoordinator(t, base.DBConfig, 3, wsURL) + defer func() { + handler.Shutdown(context.Background()) + rollerManager.Stop() + }() + + // create mock rollers. + rollers := make([]*mockRoller, 3) + for i := 0; i < len(rollers); i++ { + rollers[i] = newMockRoller(t, "roller_test"+strconv.Itoa(i), wsURL) + rollers[i].waitTaskAndSendProof(t, time.Second, false, generatedFailed) } defer func() { // close connection @@ -396,7 +461,7 @@ func testTimedoutProof(t *testing.T) { // create second mock roller, that will send valid proof. roller2 := newMockRoller(t, "roller_test"+strconv.Itoa(1), wsURL) - roller2.waitTaskAndSendProof(t, time.Second, false, true) + roller2.waitTaskAndSendProof(t, time.Second, false, verifiedSuccess) defer func() { // close connection roller2.close() @@ -441,7 +506,7 @@ func testIdleRollerSelection(t *testing.T) { rollers := make([]*mockRoller, 20) for i := 0; i < len(rollers); i++ { rollers[i] = newMockRoller(t, "roller_test"+strconv.Itoa(i), wsURL) - rollers[i].waitTaskAndSendProof(t, time.Second, false, true) + rollers[i].waitTaskAndSendProof(t, time.Second, false, verifiedSuccess) } defer func() { // close connection @@ -504,7 +569,7 @@ func testGracefulRestart(t *testing.T) { // create mock roller roller := newMockRoller(t, "roller_test", wsURL) // wait 10 seconds, coordinator restarts before roller submits proof - roller.waitTaskAndSendProof(t, 10*time.Second, false, true) + roller.waitTaskAndSendProof(t, 10*time.Second, false, verifiedSuccess) // wait for coordinator to dispatch task <-time.After(5 * time.Second) @@ -534,7 +599,7 @@ func testGracefulRestart(t *testing.T) { } // will overwrite the roller client for `SubmitProof` - roller.waitTaskAndSendProof(t, time.Millisecond*500, true, true) + roller.waitTaskAndSendProof(t, time.Millisecond*500, true, verifiedSuccess) defer roller.close() // verify proof status @@ -560,6 +625,54 @@ func testGracefulRestart(t *testing.T) { } } +func testListRollers(t *testing.T) { + // Create db handler and reset db. + assert.NoError(t, migrate.ResetDB(base.DBClient(t))) + + // Setup coordinator and ws server. + wsURL := "ws://" + randomURL() + rollerManager, handler := setupCoordinator(t, base.DBConfig, 1, wsURL) + defer func() { + handler.Shutdown(context.Background()) + rollerManager.Stop() + }() + + var names = []string{ + "roller_test_1", + "roller_test_2", + "roller_test_3", + } + + roller1 := newMockRoller(t, names[0], wsURL) + roller2 := newMockRoller(t, names[1], wsURL) + roller3 := newMockRoller(t, names[2], wsURL) + defer func() { + roller1.close() + roller2.close() + }() + + // test ListRollers API + rollers, err := rollerManager.ListRollers() + assert.NoError(t, err) + var rollersName []string + for _, roller := range rollers { + rollersName = append(rollersName, roller.Name) + } + sort.Strings(rollersName) + assert.True(t, reflect.DeepEqual(names, rollersName)) + + // test ListRollers if one roller closed. + roller3.close() + rollers, err = rollerManager.ListRollers() + assert.NoError(t, err) + var newRollersName []string + for _, roller := range rollers { + newRollersName = append(newRollersName, roller.Name) + } + sort.Strings(newRollersName) + assert.True(t, reflect.DeepEqual(names[:2], newRollersName)) +} + func setupCoordinator(t *testing.T, dbCfg *database.DBConfig, rollersPerSession uint8, wsURL string) (rollerManager *coordinator.Manager, handler *http.Server) { // Get db handler. db, err := database.NewOrmFactory(dbCfg) @@ -654,8 +767,16 @@ func (r *mockRoller) releaseTasks() { }) } +type proofStatus uint32 + +const ( + verifiedSuccess proofStatus = iota + verifiedFailed + generatedFailed +) + // Wait for the proof task, after receiving the proof task, roller submits proof after proofTime secs. -func (r *mockRoller) waitTaskAndSendProof(t *testing.T, proofTime time.Duration, reconnect bool, validProof bool) { +func (r *mockRoller) waitTaskAndSendProof(t *testing.T, proofTime time.Duration, reconnect bool, proofStatus proofStatus) { // simulating the case that the roller first disconnects and then reconnects to the coordinator // the Subscription and its `Err()` channel will be closed, and the coordinator will `freeRoller()` if reconnect { @@ -671,10 +792,10 @@ func (r *mockRoller) waitTaskAndSendProof(t *testing.T, proofTime time.Duration, r.releaseTasks() r.stopCh = make(chan struct{}) - go r.loop(t, r.client, proofTime, validProof, r.stopCh) + go r.loop(t, r.client, proofTime, proofStatus, r.stopCh) } -func (r *mockRoller) loop(t *testing.T, client *client2.Client, proofTime time.Duration, validProof bool, stopCh chan struct{}) { +func (r *mockRoller) loop(t *testing.T, client *client2.Client, proofTime time.Duration, proofStatus proofStatus, stopCh chan struct{}) { for { select { case task := <-r.taskCh: @@ -692,8 +813,10 @@ func (r *mockRoller) loop(t *testing.T, client *client2.Client, proofTime time.D Proof: &message.AggProof{}, }, } - if !validProof { + if proofStatus == generatedFailed { proof.Status = message.StatusProofError + } else if proofStatus == verifiedFailed { + proof.ProofDetail.Proof.Proof = []byte(verifier.InvalidTestProof) } assert.NoError(t, proof.Sign(r.privKey)) ok, err := client.SubmitProof(context.Background(), proof) diff --git a/coordinator/verifier/mock.go b/coordinator/verifier/mock.go index 7696ab2cf..639b287de 100644 --- a/coordinator/verifier/mock.go +++ b/coordinator/verifier/mock.go @@ -8,6 +8,8 @@ import ( "scroll-tech/coordinator/config" ) +const InvalidTestProof = "this is a invalid proof" + // Verifier represents a mock halo2 verifier. type Verifier struct { } @@ -19,5 +21,8 @@ func NewVerifier(_ *config.VerifierConfig) (*Verifier, error) { // VerifyProof always return true func (v *Verifier) VerifyProof(proof *message.AggProof) (bool, error) { + if string(proof.Proof) == InvalidTestProof { + return false, nil + } return true, nil } diff --git a/coordinator/verifier/verifier.go b/coordinator/verifier/verifier.go index 796d3a9cc..3a794de87 100644 --- a/coordinator/verifier/verifier.go +++ b/coordinator/verifier/verifier.go @@ -21,6 +21,8 @@ import ( "scroll-tech/common/message" ) +const InvalidTestProof = "this is a invalid proof" + // Verifier represents a rust ffi to a halo2 verifier. type Verifier struct { cfg *config.VerifierConfig @@ -46,7 +48,10 @@ func NewVerifier(cfg *config.VerifierConfig) (*Verifier, error) { // VerifyProof Verify a ZkProof by marshaling it and sending it to the Halo2 Verifier. func (v *Verifier) VerifyProof(proof *message.AggProof) (bool, error) { if v.cfg.MockMode { - log.Info("Verifier disabled, VerifyProof skipped") + log.Info("Mock mode, verifier disabled") + if string(proof.Proof) == InvalidTestProof { + return false, nil + } return true, nil } From 2690aeff637f8f2b4d00b8fa69e0c9234c731660 Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 24 Apr 2023 10:27:01 +0800 Subject: [PATCH 7/7] Merge develop branch and fix comments. --- bridge/relayer/l1_relayer.go | 10 +--------- bridge/relayer/l2_relayer.go | 12 ++---------- common/types/transaction.go | 4 ++-- database/orm/interface.go | 2 +- database/orm/transaction.go | 4 ++-- database/orm_test.go | 2 +- 6 files changed, 9 insertions(+), 25 deletions(-) diff --git a/bridge/relayer/l1_relayer.go b/bridge/relayer/l1_relayer.go index b4c9ecfee..a15aa0be2 100644 --- a/bridge/relayer/l1_relayer.go +++ b/bridge/relayer/l1_relayer.go @@ -192,7 +192,7 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() { return } - from, tx, err := r.gasOracleSender.SendTransaction(block.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data, 0) + _, tx, err := r.gasOracleSender.SendTransaction(block.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data, 0) if err != nil { if !errors.Is(err, sender.ErrNoAvailableAccount) && !errors.Is(err, sender.ErrFullPending) { log.Error("Failed to send setL1BaseFee tx to layer2 ", "block.Hash", block.Hash, "block.Height", block.Number, "err", err) @@ -205,11 +205,6 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() { log.Error("UpdateGasOracleStatusAndOracleTxHash failed", "block.Hash", block.Hash, "block.Height", block.Number, "err", err) return } - err = r.db.SaveScrollTx(block.Hash, from.String(), types.L1toL2GasOracleTx, tx, "") - if err != nil { - log.Error("failed to store l1 gas oracle tx message", "block.Hash", block.Hash, "block.Height", block.Number, "tx.hash", tx.Hash().String(), "err", err) - } - r.lastGasPrice = block.BaseFee log.Info("Update l1 base fee", "txHash", tx.Hash().String(), "baseFee", baseFee) } @@ -254,9 +249,6 @@ func (r *Layer1Relayer) handleConfirmLoop(ctx context.Context) { if err != nil { log.Warn("UpdateGasOracleStatusAndOracleTxHash failed", "err", err) } - if err = r.db.SetScrollTxConfirmedByID(cfm.ID, cfm.TxHash.String()); err != nil { - log.Warn("failed to delete l1 gas oracle tx data", "block.Hash", cfm.ID, "tx.Hash", cfm.TxHash.String(), "err", err) - } log.Info("transaction confirmed in layer2", "confirmation", cfm) } diff --git a/bridge/relayer/l2_relayer.go b/bridge/relayer/l2_relayer.go index f44a4b0cc..c16ff7fa6 100644 --- a/bridge/relayer/l2_relayer.go +++ b/bridge/relayer/l2_relayer.go @@ -284,7 +284,7 @@ func (r *Layer2Relayer) ProcessGasPriceOracle() { return } - from, tx, err := r.gasOracleSender.SendTransaction(batch.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data, 0) + _, tx, err := r.gasOracleSender.SendTransaction(batch.Hash, &r.cfg.GasPriceOracleContractAddress, big.NewInt(0), data, 0) if err != nil { if !errors.Is(err, sender.ErrNoAvailableAccount) && !errors.Is(err, sender.ErrFullPending) { log.Error("Failed to send setL2BaseFee tx to layer2 ", "batch.Hash", batch.Hash, "err", err) @@ -297,11 +297,6 @@ func (r *Layer2Relayer) ProcessGasPriceOracle() { log.Error("UpdateGasOracleStatusAndOracleTxHash failed", "batch.Hash", batch.Hash, "err", err) return } - // Record gas oracle tx message. - err = r.db.SaveScrollTx(batch.Hash, from.String(), types.L2toL1GasOracleTx, tx, "") - if err != nil { - log.Error("failed to save l2 gas oracle tx message", "batch.Hash", batch.Hash, "tx.Hash", tx.Hash().String(), "err", err) - } r.lastGasPrice = suggestGasPriceUint64 log.Info("Update l2 gas price", "txHash", tx.Hash().String(), "GasPrice", suggestGasPrice) } @@ -357,7 +352,7 @@ func (r *Layer2Relayer) SendCommitTx(batchData []*types.BatchData) error { log.Error("UpdateCommitTxHashAndRollupStatus failed", "hash", batchHashes[i], "index", batch.Batch.BatchIndex, "err", err) } } - // Record gas oracle tx message. + // Record batches tx message. err = r.db.SaveScrollTx(txID, from.String(), types.RollUpCommitTx, tx, strings.Join(batchHashes, ",")) if err != nil { log.Error("failed to save l2 commitBatches tx message", "batches.id", txID, "tx.hash", tx.Hash().String(), "err", err) @@ -615,9 +610,6 @@ func (r *Layer2Relayer) handleConfirmLoop(ctx context.Context) { if err != nil { log.Warn("UpdateL2GasOracleStatusAndOracleTxHash failed", "err", err) } - if err = r.db.SetScrollTxConfirmedByID(cfm.ID, cfm.TxHash.String()); err != nil { - log.Warn("failed to delete l2 gas oracle tx data", "batch.Hash", cfm.ID, "tx.Hash", cfm.TxHash.String(), "err", err) - } log.Info("transaction confirmed in layer1", "confirmation", cfm) } } diff --git a/common/types/transaction.go b/common/types/transaction.go index db938e970..68a2e1d92 100644 --- a/common/types/transaction.go +++ b/common/types/transaction.go @@ -6,8 +6,8 @@ import "database/sql" type ScrollTxType int const ( - // UndefinedTx undefined scroll tx type - UndefinedTx ScrollTxType = iota + // UndefinedScrollTx undefined scroll tx type + UndefinedScrollTx ScrollTxType = iota // L1toL2MessageTx is sent by l1 relayer but to L2 L1toL2MessageTx // L1toL2GasOracleTx is sent by l1 relayer but to L2 diff --git a/database/orm/interface.go b/database/orm/interface.go index 0e0b5aa17..4f8a66125 100644 --- a/database/orm/interface.go +++ b/database/orm/interface.go @@ -116,7 +116,7 @@ type L2MessageOrm interface { type ScrollTxOrm interface { SaveScrollTx(id, sender string, txType types.ScrollTxType, tx *etypes.Transaction, extraData string) error SetScrollTxConfirmedByID(hash string, txHash string) error - GetTxByID(id string) (*types.ScrollTx, error) + GetScrollTxByID(id string) (*types.ScrollTx, error) GetL1TxMessages(fields map[string]interface{}, args ...string) ([]*types.ScrollTx, error) GetL2TxMessages(fields map[string]interface{}, args ...string) ([]*types.ScrollTx, error) GetBlockBatchTxMessages(fields map[string]interface{}, args ...string) ([]*types.ScrollTx, error) diff --git a/database/orm/transaction.go b/database/orm/transaction.go index 95234791c..ae44cd2e7 100644 --- a/database/orm/transaction.go +++ b/database/orm/transaction.go @@ -52,8 +52,8 @@ func (t *scrollTxOrm) SetScrollTxConfirmedByID(id string, txHash string) error { return err } -// GetTxByID returns tx message by message id. -func (t *scrollTxOrm) GetTxByID(id string) (*stypes.ScrollTx, error) { +// GetScrollTxByID returns tx message by message id. +func (t *scrollTxOrm) GetScrollTxByID(id string) (*stypes.ScrollTx, error) { db := t.db row := db.QueryRowx(db.Rebind("SELECT id, tx_hash, sender, nonce, target, value, data FROM scroll_transaction WHERE id = ?"), id) txMsg := &stypes.ScrollTx{} diff --git a/database/orm_test.go b/database/orm_test.go index 4827f6765..6c14cc75e 100644 --- a/database/orm_test.go +++ b/database/orm_test.go @@ -481,7 +481,7 @@ func testTxOrmSaveTxAndGetTxByHash(t *testing.T) { err = ormTx.SetScrollTxConfirmedByID("1", signedTx.Hash().String()) assert.NoError(t, err) - savedTx, err := ormTx.GetTxByID("1") + savedTx, err := ormTx.GetScrollTxByID("1") assert.NoError(t, err) assert.Equal(t, signedTx.Hash().String(), savedTx.TxHash.String)