test: fevm: add in tests for deploying, destroying contracts, recursive calls, sending value (#10082)

adds the following tests to itests/fevm_test.go:
 - recursive tests
 - delegate call tests
 - delegate call recursive tests
 - revert tests
 - destruct tests
 - contract deploy address tests
 - send value to contracts
 - gas limit on value transfer tests
 - sending value to destroyed contracts
adds the test to itests/fevm_address_test.go:
 - deploy contract and confirm address is different second deploy
This commit is contained in:
snissn 2023-01-31 19:13:13 -10:00 committed by GitHub
parent a38e63998e
commit 9060c474da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1036 additions and 96 deletions

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5061001f61002460201b60201c565b61003d565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60848061004b6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea26469706673582212208d48a69a112633756d84552847610df29b02ac89dd39e4e295066e99a45e809664736f6c63430008110033

View File

@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
contract AutoSelfDestruct {
constructor() {
destroy();
}
function destroy() public {
selfdestruct(payable(msg.sender));
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506103ca806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806358f5ebb614610030575b600080fd5b61004a60048036038101906100459190610123565b610060565b6040516100579190610191565b60405180910390f35b60008082604051610070906100db565b61007a91906101bb565b604051809103906000f080158015610096573d6000803e3d6000fd5b5090507f3a5c468996b00310e3e82919e3af9cce21d49c40c39a2627a9f946e1a54d886232846040516100ca9291906101d6565b60405180910390a180915050919050565b6101958061020083390190565b600080fd5b6000819050919050565b610100816100ed565b811461010b57600080fd5b50565b60008135905061011d816100f7565b92915050565b600060208284031215610139576101386100e8565b5b60006101478482850161010e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017b82610150565b9050919050565b61018b81610170565b82525050565b60006020820190506101a66000830184610182565b92915050565b6101b5816100ed565b82525050565b60006020820190506101d060008301846101ac565b92915050565b60006040820190506101eb6000830185610182565b6101f860208301846101ac565b939250505056fe608060405234801561001057600080fd5b506040516101953803806101958339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b60e0806100b56000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80638381f58a146037578063eeb4e367146051575b600080fd5b603d606b565b604051604891906091565b60405180910390f35b60576071565b604051606291906091565b60405180910390f35b60005481565b60008054905090565b6000819050919050565b608b81607a565b82525050565b600060208201905060a460008301846084565b9291505056fea2646970667358221220451c388f24a935fc5f5eef536207cbd982254ac8521d49937bb10e5079e3924164736f6c63430008110033a264697066735822122027da159d84a9bdcd5aff5755c4602f7099db638f7a95d715c76454c99511146f64736f6c63430008110033

View File

@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
contract Test_contract {
uint256 public number;
constructor(uint256 _number) {
number = _number;
}
function get_number() public view returns (uint256) {
return number;
}
}
contract App {
event NewTest(address sender, uint256 number);
function new_Test(uint256 number)
public
returns (address)
{
address mynew = address(new Test_contract({_number: number}));
emit NewTest(tx.origin, number);
return mynew;
}
}

View File

@ -1 +1 @@
608060405234801561001057600080fd5b50610477806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780638ada066e14610064578063d1e0f3081461008f575b600080fd5b34801561004557600080fd5b5061004e6100bf565b60405161005b919061022c565b60405180910390f35b34801561007057600080fd5b506100796100c5565b604051610086919061022c565b60405180910390f35b6100a960048036038101906100a491906102d6565b6100ce565b6040516100b6919061022c565b60405180910390f35b60005481565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16836040516024016100f9919061022c565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101839190610387565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b5050905080610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101fe90610421565b60405180910390fd5b60005491505092915050565b6000819050919050565b61022681610213565b82525050565b6000602082019050610241600083018461021d565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102778261024c565b9050919050565b6102878161026c565b811461029257600080fd5b50565b6000813590506102a48161027e565b92915050565b6102b381610213565b81146102be57600080fd5b50565b6000813590506102d0816102aa565b92915050565b600080604083850312156102ed576102ec610247565b5b60006102fb85828601610295565b925050602061030c858286016102c1565b9150509250929050565b600081519050919050565b600081905092915050565b60005b8381101561034a57808201518184015260208101905061032f565b60008484015250505050565b600061036182610316565b61036b8185610321565b935061037b81856020860161032c565b80840191505092915050565b60006103938284610356565b915081905092915050565b600082825260208201905092915050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b600061040b60228361039e565b9150610416826103af565b604082019050919050565b6000602082019050818103600083015261043a816103fe565b905091905056fea26469706673582212203663909b8221e9b87047be99420c00339af1430c085260df209b909ed8e0f05164736f6c63430008110033
608060405234801561001057600080fd5b5061087e806100206000396000f3fe6080604052600436106100555760003560e01c80630712ede21461005a57806361bc221a1461008a5780637da3c3ab146100b55780638ada066e146100cc578063bed56f47146100f7578063d1e0f30814610127575b600080fd5b610074600480360381019061006f919061060f565b610157565b604051610081919061065e565b60405180910390f35b34801561009657600080fd5b5061009f610298565b6040516100ac919061065e565b60405180910390f35b3480156100c157600080fd5b506100ca61029e565b005b3480156100d857600080fd5b506100e16102e1565b6040516100ee919061065e565b60405180910390f35b610111600480360381019061010c919061060f565b6102ea565b60405161011e919061065e565b60405180910390f35b610141600480360381019061013c919061060f565b610431565b60405161014e919061065e565b60405180910390f35b6000808373ffffffffffffffffffffffffffffffffffffffff1683604051602401610182919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161020c91906106ea565b600060405180830381855af49150503d8060008114610247576040519150601f19603f3d011682016040523d82523d6000602084013e61024c565b606091505b505090506000610291576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102889061075e565b60405180910390fd5b5092915050565b60005481565b60006102df576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d69061075e565b60405180910390fd5b565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16848460405160240161031792919061078d565b6040516020818303038152906040527fbed56f47000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516103a191906106ea565b600060405180830381855af49150503d80600081146103dc576040519150601f19603f3d011682016040523d82523d6000602084013e6103e1565b606091505b5050905080610425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161041c90610828565b60405180910390fd5b60005491505092915050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405160240161045c919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104e691906106ea565b600060405180830381855af49150503d8060008114610521576040519150601f19603f3d011682016040523d82523d6000602084013e610526565b606091505b505090508061056a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056190610828565b60405180910390fd5b60005491505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a68261057b565b9050919050565b6105b68161059b565b81146105c157600080fd5b50565b6000813590506105d3816105ad565b92915050565b6000819050919050565b6105ec816105d9565b81146105f757600080fd5b50565b600081359050610609816105e3565b92915050565b6000806040838503121561062657610625610576565b5b6000610634858286016105c4565b9250506020610645858286016105fa565b9150509250929050565b610658816105d9565b82525050565b6000602082019050610673600083018461064f565b92915050565b600081519050919050565b600081905092915050565b60005b838110156106ad578082015181840152602081019050610692565b60008484015250505050565b60006106c482610679565b6106ce8185610684565b93506106de81856020860161068f565b80840191505092915050565b60006106f682846106b9565b915081905092915050565b600082825260208201905092915050565b7f696e74656e74696f6e616c6c79207468726f77696e67206572726f7200000000600082015250565b6000610748601c83610701565b915061075382610712565b602082019050919050565b600060208201905081810360008301526107778161073b565b9050919050565b6107878161059b565b82525050565b60006040820190506107a2600083018561077e565b6107af602083018461064f565b9392505050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b6000610812602283610701565b915061081d826107b6565b604082019050919050565b6000602082019050818103600083015261084181610805565b905091905056fea2646970667358221220b2a3ae7e2a9ffc78e3e2a7aadb2885435c5e51aa9d3f07372a0dffb6238aa1db64736f6c63430008110033

View File

@ -5,13 +5,29 @@ contract DelegatecallStorage {
uint public counter;
function getCounter() public view returns (uint){
return counter;
return counter;
}
function setVars(address _contract, uint _counter) public payable returns (uint){
(bool success, ) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _counter)
);
require(success, 'Error message: Delegatecall failed');
return counter;
}
function setVarsSelf(address _contract, uint _counter) public payable returns (uint){
(bool success, ) = _contract.delegatecall(
abi.encodeWithSignature("setVarsSelf(address,uint256)", _contract, _counter)
);
require(success, 'Error message: Delegatecall failed');
return counter;
}
function setVarsRevert(address _contract, uint _counter) public payable returns (uint){
(bool success, ) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _counter)
);
require(success, 'Error message: Delegatecall failed');
return counter;
require(false,"intentionally throwing error");
}
function revert() public{
require(false,"intentionally throwing error");
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5061027c806100206000396000f3fe6080604052600436106100385760003560e01c80630bc07a88146100435780633da767881461005a578063f0ba84401461008557610039565b5b6100416100c2565b005b34801561004f57600080fd5b506100586100c2565b005b34801561006657600080fd5b5061006f61010d565b60405161007c9190610156565b60405180910390f35b34801561009157600080fd5b506100ac60048036038101906100a791906101a2565b610119565b6040516100b99190610156565b60405180910390f35b60005b606481101561010a5760008190806001815401808255809150506001900390600052602060002001600090919091909150558080610102906101fe565b9150506100c5565b50565b60008080549050905090565b6000818154811061012957600080fd5b906000526020600020016000915090505481565b6000819050919050565b6101508161013d565b82525050565b600060208201905061016b6000830184610147565b92915050565b600080fd5b61017f8161013d565b811461018a57600080fd5b50565b60008135905061019c81610176565b92915050565b6000602082840312156101b8576101b7610171565b5b60006101c68482850161018d565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006102098261013d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361023b5761023a6101cf565b5b60018201905091905056fea2646970667358221220c56d78e0c60a01681eee1b76c95e7b214d16a512c944e31cfee71eb727c1e44064736f6c63430008110033

View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract GasLimitTest {
address payable receiver;
constructor(){
address mynew = address(new GasLimitTestReceiver());
receiver = payable(mynew);
}
function send() public payable{
receiver.transfer(msg.value);
}
function expensiveTest() public{
GasLimitTestReceiver(receiver).expensive();
}
function getDataLength() public returns (uint256) {
return GasLimitTestReceiver(receiver).getDataLength();
}
}
contract GasLimitTestReceiver {
uint256[] public data;
fallback() external payable {
expensive();
}
function expensive() public{
for (uint256 i = 0; i < 100; i++) {
data.push(i);
}
}
function getDataLength() public view returns (uint256) {
return data.length;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220c0f2da1b01178b54afba1ddf14f30307a03cdb66f61b4e1dc342079561db009064736f6c63430008110033

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract GasLimitTestReceiver {
function x() public returns (uint256){
return 7;
}
}

View File

@ -0,0 +1 @@
6080604052348015600f57600080fd5b50604780601d6000396000f3fe6080604052348015600f57600080fd5b00fea26469706673582212200cd38951eddebe3692dc8921afb65a04fbe64e10d5e261806330156459bf227264736f6c63430008110033

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
//sending eth should fall because fallback is not payable
contract NotPayable {
fallback() external {}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506102d9806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063032cec451461005c57806372536f3c1461007a57806399fdb86e14610098578063d2aac3ea146100b6578063ec49254c146100d4575b600080fd5b610064610104565b60405161007191906101c7565b60405180910390f35b610082610115565b60405161008f91906101c7565b60405180910390f35b6100a0610126565b6040516100ad91906101c7565b60405180910390f35b6100be610137565b6040516100cb91906101c7565b60405180910390f35b6100ee60048036038101906100e99190610213565b610148565b6040516100fb91906101c7565b60405180910390f35b60006101106001610148565b905090565b6000610121600a610148565b905090565b60006101326002610148565b905090565b60006101436000610148565b905090565b6000808211156101a5577f3110e0ccd510fcbb471c933ad12161c459e8735b5bde2eea61a659c2e2f0a3cc8260405161018191906101c7565b60405180910390a161019e600183610199919061026f565b610148565b90506101a9565b8190505b919050565b6000819050919050565b6101c1816101ae565b82525050565b60006020820190506101dc60008301846101b8565b92915050565b600080fd5b6101f0816101ae565b81146101fb57600080fd5b50565b60008135905061020d816101e7565b92915050565b600060208284031215610229576102286101e2565b5b6000610237848285016101fe565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061027a826101ae565b9150610285836101ae565b925082820390508181111561029d5761029c610240565b5b9291505056fea26469706673582212206178e15eb87e2f766b94ec09a6a860878c93d72a31de225e1684da1755f917c764736f6c63430008110033

View File

@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Recursive {
event RecursiveCallEvent(uint256 count);
function recursive10() public returns (uint256){
return recursiveCall(10);
}
function recursive2() public returns (uint256){
return recursiveCall(2);
}
function recursive1() public returns (uint256){
return recursiveCall(1);
}
function recursive0() public returns (uint256){
return recursiveCall(0);
}
function recursiveCall(uint256 count) public returns (uint256) {
if (count > 0) {
emit RecursiveCallEvent(count);
return recursiveCall(count-1);
}
return count;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b50610459806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633af3f24f1461003b578063ec49254c14610059575b600080fd5b610043610089565b6040516100509190610221565b60405180910390f35b610073600480360381019061006e919061026d565b61008f565b6040516100809190610221565b60405180910390f35b60005481565b60007faab69767807d0ab32f0099452739da31b76ecd3e8694bb49898829c8bf9d063582306040516100c29291906102db565b60405180910390a160016000808282546100dc9190610333565b9250508190555060018211156101ff576001826100f99190610367565b91506000803073ffffffffffffffffffffffffffffffffffffffff16846040516024016101269190610221565b6040516020818303038152906040527fec49254c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101b0919061040c565b600060405180830381855af49150503d80600081146101eb576040519150601f19603f3d011682016040523d82523d6000602084013e6101f0565b606091505b50915091508392505050610203565b8190505b919050565b6000819050919050565b61021b81610208565b82525050565b60006020820190506102366000830184610212565b92915050565b600080fd5b61024a81610208565b811461025557600080fd5b50565b60008135905061026781610241565b92915050565b6000602082840312156102835761028261023c565b5b600061029184828501610258565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102c58261029a565b9050919050565b6102d5816102ba565b82525050565b60006040820190506102f06000830185610212565b6102fd60208301846102cc565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061033e82610208565b915061034983610208565b925082820190508082111561036157610360610304565b5b92915050565b600061037282610208565b915061037d83610208565b925082820390508181111561039557610394610304565b5b92915050565b600081519050919050565b600081905092915050565b60005b838110156103cf5780820151818401526020810190506103b4565b60008484015250505050565b60006103e68261039b565b6103f081856103a6565b93506104008185602086016103b1565b80840191505092915050565b600061041882846103db565b91508190509291505056fea2646970667358221220e70fbbfaccd3fbb084623d6d06895fba1abc5fefc181215b56ab1e43db79c7fb64736f6c63430008110033

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
contract RecursiveDelegatecall {
event RecursiveCallEvent(uint256 count, address self);
uint256 public totalCalls;
function recursiveCall(uint256 count) public returns (uint256) {
emit RecursiveCallEvent(count, address(this));
totalCalls += 1;
if (count > 1) {
count -= 1;
(bool success, bytes memory returnedData) = address(this)
.delegatecall(
abi.encodeWithSignature("recursiveCall(uint256)", count)
);
return count;
}
return count;
}
}

View File

@ -0,0 +1 @@
6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220d4aa109d42268586e7ce4f0fafb0ebbd04c412c6c7e8c387b009a08ecdff864264736f6c63430008110033

View File

@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
contract SelfDestruct {
function destroy() public {
selfdestruct(payable(msg.sender));
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,211 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
pragma experimental ABIEncoderV2;
contract Test_contract {
uint256 timestamp;
address sender;
string text;
uint256 number;
constructor(string memory _text, uint256 _number) {
sender = tx.origin;
timestamp = block.timestamp;
text = _text;
number = _number;
}
function getall()
public
view
returns (
address,
uint256,
address,
string memory,
uint256
)
{
return (address(this), timestamp, sender, text, number);
}
function get_timestamp() public view returns (uint256) {
return timestamp;
}
function get_sender() public view returns (address) {
return sender;
}
function get_text() public view returns (string memory) {
return text;
}
function get_number() public view returns (uint256) {
return number;
}
}
contract App {
address[] Test_list;
uint256 Test_list_length;
function get_Test_list_length() public view returns (uint256) {
return Test_list_length;
}
struct Test_getter {
address _address;
uint256 timestamp;
address sender;
string text;
uint256 number;
}
function get_Test_N(uint256 index)
public
view
returns (
address,
uint256,
address,
string memory,
uint256
)
{
return Test_contract(Test_list[index]).getall();
}
function get_first_Test_N(uint256 count, uint256 offset)
public
view
returns (Test_getter[] memory)
{
Test_getter[] memory getters = new Test_getter[](count);
for (uint256 i = offset; i < count; i++) {
Test_contract myTest = Test_contract(Test_list[i + offset]);
getters[i - offset]._address = address(myTest);
getters[i - offset].timestamp = myTest.get_timestamp();
getters[i - offset].sender = myTest.get_sender();
getters[i - offset].text = myTest.get_text();
getters[i - offset].number = myTest.get_number();
}
return getters;
}
function get_last_Test_N(uint256 count, uint256 offset)
public
view
returns (Test_getter[] memory)
{
Test_getter[] memory getters = new Test_getter[](count);
for (uint256 i = 0; i < count; i++) {
Test_contract myTest =
Test_contract(Test_list[Test_list_length - i - offset - 1]);
getters[i]._address = address(myTest);
getters[i].timestamp = myTest.get_timestamp();
getters[i].sender = myTest.get_sender();
getters[i].text = myTest.get_text();
getters[i].number = myTest.get_number();
}
return getters;
}
function get_Test_user_length(address user) public view returns (uint256) {
return user_map[user].Test_list_length;
}
function get_Test_user_N(address user, uint256 index)
public
view
returns (
address,
uint256,
address,
string memory,
uint256
)
{
return Test_contract(user_map[user].Test_list[index]).getall();
}
function get_last_Test_user_N(
address user,
uint256 count,
uint256 offset
) public view returns (Test_getter[] memory) {
Test_getter[] memory getters = new Test_getter[](count);
for (uint256 i = offset; i < count; i++) {
getters[i - offset]._address = user_map[user].Test_list[i + offset];
getters[i - offset].timestamp = Test_contract(
user_map[user].Test_list[i + offset]
)
.get_timestamp();
getters[i - offset].sender = Test_contract(
user_map[user].Test_list[i + offset]
)
.get_sender();
getters[i - offset].text = Test_contract(
user_map[user].Test_list[i + offset]
)
.get_text();
getters[i - offset].number = Test_contract(
user_map[user].Test_list[i + offset]
)
.get_number();
}
return getters;
}
struct UserInfo {
address owner;
bool exists;
address[] Test_list;
uint256 Test_list_length;
}
mapping(address => UserInfo) public user_map;
address[] UserInfoList;
uint256 UserInfoListLength;
event NewTest(address sender);
function new_Test(string memory text, uint256 number)
public
returns (address)
{
address mynew =
address(new Test_contract({_text: text, _number: number}));
if (!user_map[tx.origin].exists) {
user_map[tx.origin] = create_user_on_new_Test(mynew);
}
user_map[tx.origin].Test_list.push(mynew);
user_map[tx.origin].Test_list_length += 1;
Test_list.push(mynew);
Test_list_length += 1;
emit NewTest(tx.origin);
return mynew;
}
function create_user_on_new_Test(address addr)
private
returns (UserInfo memory)
{
address[] memory Test_list_;
UserInfoList.push(addr);
return
UserInfo({
exists: true,
owner: addr,
Test_list: Test_list_,
Test_list_length: 0
});
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506106dc806100206000396000f3fe60806040526004361061002d5760003560e01c8063dbdc275d14610072578063fd75295a1461009d5761006d565b3661006d577f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd679308333460405161006392919061020f565b60405180910390a1005b600080fd5b34801561007e57600080fd5b506100876100b9565b6040516100949190610238565b60405180910390f35b6100b760048036038101906100b29190610296565b610125565b005b6000806040516100c8906101a8565b604051809103906000f0801580156100e4573d6000803e3d6000fd5b5090507f8db3b20eed31d927a4f613b5c11765212e129cf726d025649650665569ea683b816040516101169190610238565b60405180910390a18091505090565b7f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd6793088134604051610156929190610322565b60405180910390a18073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156101a4573d6000803e3d6000fd5b5050565b61035b8061034c83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e0826101b5565b9050919050565b6101f0816101d5565b82525050565b6000819050919050565b610209816101f6565b82525050565b600060408201905061022460008301856101e7565b6102316020830184610200565b9392505050565b600060208201905061024d60008301846101e7565b92915050565b600080fd5b6000610263826101b5565b9050919050565b61027381610258565b811461027e57600080fd5b50565b6000813590506102908161026a565b92915050565b6000602082840312156102ac576102ab610253565b5b60006102ba84828501610281565b91505092915050565b6000819050919050565b60006102e86102e36102de846101b5565b6102c3565b6101b5565b9050919050565b60006102fa826102cd565b9050919050565b600061030c826102ef565b9050919050565b61031c81610301565b82525050565b60006040820190506103376000830185610313565b6103446020830184610200565b939250505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102fb806100606000396000f3fe60806040526004361061002d5760003560e01c806337cb6570146100725780639cb8a26a1461007c5761006d565b3661006d577fe1494f56a1ccfd8c7361f2ca5b8fd2b1a2fe11773821ac29534f09f4a0637d603334604051610063929190610214565b60405180910390a1005b600080fd5b61007a610093565b005b34801561008857600080fd5b50610091610155565b005b7f76cff203b0794a9e9013657ecb172f2d6e8de5941fd11a6bfbc0fb6014a5f07960008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16476040516100e492919061029c565b60405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610152573d6000803e3d6000fd5b50565b7f1cbd47e7b0f55dc1a45ba8ebada53eaa1712b3e3e86f49a12c008ff22334569060405160405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e5826101ba565b9050919050565b6101f5816101da565b82525050565b6000819050919050565b61020e816101fb565b82525050565b600060408201905061022960008301856101ec565b6102366020830184610205565b9392505050565b6000819050919050565b600061026261025d610258846101ba565b61023d565b6101ba565b9050919050565b600061027482610247565b9050919050565b600061028682610269565b9050919050565b6102968161027b565b82525050565b60006040820190506102b1600083018561028d565b6102be6020830184610205565b939250505056fea2646970667358221220bdf21908b1c91973a8440fe81130e0077cf83c8f8e9a053d8a0c3063391aa40764736f6c63430008110033a26469706673582212202e514fe078dfcf4f1142a088c57cfa71ada74d72ee0cc4a46b7e1141cdbaeeed64736f6c63430008110033

View File

@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17;
contract A {
event LogCreateB(address _bAddress);
event LogSendEthA(address _bAddress, uint _value);
event LogReceiveEthA(address _bAddress, uint _value);
// Function to create a new instance of contract B and return its address
function createB() public returns (address) {
address bAddress = address(new B());
emit LogCreateB(bAddress);
return bAddress;
}
// Payable method to accept eth and an address for B and send the eth to B
function sendEthToB(address payable _bAddress) public payable {
emit LogSendEthA(_bAddress, msg.value);
_bAddress.transfer(msg.value);
}
// Payable function to accept the eth
receive() external payable {
emit LogSendEthA(msg.sender, msg.value);
}
}
contract B {
event LogSelfDestruct();
event LogSendEthToA(address _to, uint _value);
event LogReceiveEth(address from, uint value);
address payable creator;
constructor(){
creator = payable(msg.sender);
}
// Payable function to accept the eth
receive() external payable {
emit LogReceiveEth(msg.sender, msg.value);
}
// Method to send ether to contract A
function sendEthToA() public payable {
emit LogSendEthToA(creator,address(this).balance);
creator.transfer(address(this).balance);
}
// Self destruct method to send eth to its creator
function selfDestruct() public {
emit LogSelfDestruct();
selfdestruct(creator);
}
}

View File

@ -1,6 +1,19 @@
set -eu
set -o pipefail
#use the solc compiler https://docs.soliditylang.org/en/v0.8.17/installing-solidity.html
# to compile all of the .sol files to their corresponding evm binary files stored as .hex
# solc outputs to stdout a format that we just want to grab the last line of and then remove the trailing newline on that line
find -type f -name \*.sol -print0 |
xargs -0 -I{} bash -c 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)'
find . -name \*.sol -print0 |
xargs -0 -I{} bash -euc -o pipefail 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)'
#for these contracts we have 2 contracts in the same solidity file
#this command grabs the correct bytecode for us
for filename in Constructor TestApp ValueSender ; do
echo $filename
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
done

View File

@ -1099,7 +1099,8 @@ func invokeAndWaitUntilAllOnChain(t *testing.T, client *kit.TestFullNode, invoca
}
}
}
ret := client.EVM().InvokeSolidity(ctx, inv.Sender, inv.Target, inv.Selector, inv.Data)
ret, err := client.EVM().InvokeSolidity(ctx, inv.Sender, inv.Target, inv.Selector, inv.Data)
require.NoError(err)
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
invocationMap[ret.Message] = inv

View File

@ -6,7 +6,6 @@ import (
"encoding/hex"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/sha3"
@ -44,14 +43,43 @@ func effectiveEthAddressForCreate(t *testing.T, sender address.Address) ethtypes
panic("unreachable")
}
func createAndDeploy(ctx context.Context, t *testing.T, client *kit.TestFullNode, fromAddr address.Address, contract []byte) *api.MsgLookup {
// Create and deploy evm actor
method := builtintypes.MethodsEAM.CreateExternal
contractParams := abi.CborBytes(contract)
params, actorsErr := actors.SerializeParams(&contractParams)
require.NoError(t, actorsErr)
createMsg := &types.Message{
To: builtintypes.EthereumAddressManagerActorAddr,
From: fromAddr,
Value: big.Zero(),
Method: method,
Params: params,
}
smsg, err := client.MpoolPushMessage(ctx, createMsg, nil)
require.NoError(t, err)
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
require.NoError(t, err)
require.Equal(t, exitcode.Ok, wait.Receipt.ExitCode)
return wait
}
func getEthAddressTX(ctx context.Context, t *testing.T, client *kit.TestFullNode, wait *api.MsgLookup, ethAddr ethtypes.EthAddress) ethtypes.EthAddress {
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
var createExternalReturn eam.CreateExternalReturn
err := createExternalReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return))
require.NoError(t, err)
createdEthAddr, err := ethtypes.CastEthAddress(createExternalReturn.EthAddress[:])
require.NoError(t, err)
return createdEthAddr
}
func TestAddressCreationBeforeDeploy(t *testing.T) {
kit.QuietMiningLogs()
blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
// install contract
@ -72,22 +100,11 @@ func TestAddressCreationBeforeDeploy(t *testing.T) {
contractFilAddr, err := ethAddr.ToFilecoinAddress()
require.NoError(t, err)
// Send contract address some funds
//transfer half the wallet balance
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
require.NoError(t, err)
sendAmount := big.Div(bal, big.NewInt(2))
sendMsg := &types.Message{
From: fromAddr,
To: contractFilAddr,
Value: sendAmount,
}
signedMsg, err := client.MpoolPushMessage(ctx, sendMsg, nil)
require.NoError(t, err)
mLookup, err := client.StateWaitMsg(ctx, signedMsg.Cid(), 3, api.LookbackNoLimit, true)
require.NoError(t, err)
require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode)
client.EVM().TransferValueOrFail(ctx, fromAddr, contractFilAddr, sendAmount)
// Check if actor at new address is a placeholder actor
actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
@ -95,40 +112,69 @@ func TestAddressCreationBeforeDeploy(t *testing.T) {
require.True(t, builtin.IsPlaceholderActor(actor.Code))
// Create and deploy evm actor
method := builtintypes.MethodsEAM.CreateExternal
contractParams := abi.CborBytes(contract)
params, err := actors.SerializeParams(&contractParams)
require.NoError(t, err)
createMsg := &types.Message{
To: builtintypes.EthereumAddressManagerActorAddr,
From: fromAddr,
Value: big.Zero(),
Method: method,
Params: params,
}
smsg, err := client.MpoolPushMessage(ctx, createMsg, nil)
require.NoError(t, err)
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
require.NoError(t, err)
require.Equal(t, exitcode.Ok, wait.Receipt.ExitCode)
wait := createAndDeploy(ctx, t, client, fromAddr, contract)
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
var createExternalReturn eam.CreateExternalReturn
err = createExternalReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return))
require.NoError(t, err)
createdEthAddr, err := ethtypes.CastEthAddress(createExternalReturn.EthAddress[:])
require.NoError(t, err)
createdEthAddr := getEthAddressTX(ctx, t, client, wait, ethAddr)
require.Equal(t, ethAddr, createdEthAddr)
// Check if newly deployed actor still has funds
actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
require.NoError(t, err)
require.Equal(t, actorPostCreate.Balance, sendAmount)
require.True(t, builtin.IsEvmActor(actorPostCreate.Code))
}
func TestDeployAddressMultipleTimes(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
// install contract
contractHex, err := os.ReadFile("contracts/SimpleCoin.hex")
require.NoError(t, err)
contract, err := hex.DecodeString(string(contractHex))
require.NoError(t, err)
fromAddr, err := client.WalletDefaultAddress(ctx)
require.NoError(t, err)
// We hash the f1/f3 address into the EVM's address space when deploying contracts from
// accounts.
effectiveEvmAddress := effectiveEthAddressForCreate(t, fromAddr)
ethAddr := client.EVM().ComputeContractAddress(effectiveEvmAddress, 1)
contractFilAddr, err := ethAddr.ToFilecoinAddress()
require.NoError(t, err)
// Send contract address small funds to init
sendAmount := big.NewInt(2)
client.EVM().TransferValueOrFail(ctx, fromAddr, contractFilAddr, sendAmount)
// Check if actor at new address is a placeholder actor
actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
require.NoError(t, err)
require.True(t, builtin.IsPlaceholderActor(actor.Code))
// Create and deploy evm actor
wait := createAndDeploy(ctx, t, client, fromAddr, contract)
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
createdEthAddr := getEthAddressTX(ctx, t, client, wait, ethAddr)
require.Equal(t, ethAddr, createdEthAddr)
// Check if newly deployed actor still has funds
actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
require.NoError(t, err)
require.Equal(t, actorPostCreate.Balance, sendAmount)
require.True(t, builtin.IsEvmActor(actorPostCreate.Code))
// Create and deploy evm actor
wait = createAndDeploy(ctx, t, client, fromAddr, contract)
// Check that this time eth address returned from CreateExternal is not the same as eth address predicted at the start
createdEthAddr = getEthAddressTX(ctx, t, client, wait, ethAddr)
require.NotEqual(t, ethAddr, createdEthAddr)
}

View File

@ -64,20 +64,23 @@ func TestFEVMEvents(t *testing.T) {
require.Empty(res.Results)
// log a zero topic event with data
ret := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil)
ret, err := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil)
require.NoError(err)
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
require.NotNil(ret.Receipt.EventsRoot)
fmt.Println(ret)
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
// log a zero topic event with no data
ret = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x01}, nil)
ret, err = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x01}, nil)
require.NoError(err)
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
fmt.Println(ret)
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
// log a four topic event with data
ret = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x02}, nil)
ret, err = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x02}, nil)
require.NoError(err)
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
fmt.Println(ret)
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))

View File

@ -1,15 +1,17 @@
package itests
import (
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/go-state-types/manifest"
@ -38,19 +40,139 @@ func inputDataFromFrom(ctx context.Context, t *testing.T, client *kit.TestFullNo
return inputData
}
func setupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *kit.TestFullNode) {
kit.QuietMiningLogs()
blockTime := 5 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMiningMustPost(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
return ctx, cancel, client
func decodeOutputToUint64(output []byte) (uint64, error) {
var result uint64
buf := bytes.NewReader(output[len(output)-8:])
err := binary.Read(buf, binary.BigEndian, &result)
return result, err
}
func buildInputFromuint64(number uint64) []byte {
// Convert the number to a binary uint64 array
binaryNumber := make([]byte, 8)
binary.BigEndian.PutUint64(binaryNumber, number)
return inputDataFromArray(binaryNumber)
}
// recursive delegate calls that fail due to gas limits are currently getting to 229 iterations
// before running out of gas
func recursiveDelegatecallFail(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) {
expectedIterationsBeforeFailing := int(229)
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
t.Log("recursion count - ", count)
inputData := buildInputFromuint64(count)
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
require.NoError(t, err)
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
require.NoError(t, err)
resultUint, err := decodeOutputToUint64(result)
require.NoError(t, err)
require.NotEqual(t, int(resultUint), int(count))
require.Equal(t, expectedIterationsBeforeFailing, int(resultUint))
}
func recursiveDelegatecallSuccess(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) {
t.Log("Count - ", count)
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
inputData := buildInputFromuint64(count)
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
require.NoError(t, err)
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
require.NoError(t, err)
resultUint, err := decodeOutputToUint64(result)
require.NoError(t, err)
require.Equal(t, int(count), int(resultUint))
}
// TestFEVMRecursive does a basic fevm contract installation and invocation
func TestFEVMRecursive(t *testing.T) {
callCounts := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 230, 330}
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
filename := "contracts/Recursive.hex"
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
// Successful calls
for _, callCount := range callCounts {
callCount := callCount // linter unhappy unless callCount is local to loop
t.Run(fmt.Sprintf("TestFEVMRecursive%d", callCount), func(t *testing.T) {
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(callCount))
require.NoError(t, err)
})
}
}
func TestFEVMRecursiveFail(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
filename := "contracts/Recursive.hex"
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
// Unsuccessful calls
failCallCounts := []uint64{340, 400, 600, 850, 1000}
for _, failCallCount := range failCallCounts {
failCallCount := failCallCount // linter unhappy unless callCount is local to loop
t.Run(fmt.Sprintf("TestFEVMRecursiveFail%d", failCallCount), func(t *testing.T) {
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(failCallCount))
require.Error(t, err)
require.Equal(t, exitcode.ExitCode(23), wait.Receipt.ExitCode)
})
}
}
func TestFEVMRecursive1(t *testing.T) {
callCount := 1
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
filename := "contracts/Recursive.hex"
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
_, ret, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursive1()", []byte{})
require.NoError(t, err)
events := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)
require.Equal(t, callCount, len(events))
}
func TestFEVMRecursive2(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
filename := "contracts/Recursive.hex"
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
_, ret, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursive2()", []byte{})
require.NoError(t, err)
events := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)
require.Equal(t, 2, len(events))
}
// TestFEVMBasic does a basic fevm contract installation and invocation
// recursive delegate call succeeds up to 238 times
func TestFEVMRecursiveDelegatecall(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
filename := "contracts/RecursiveDelegeatecall.hex"
//success with 238 or fewer calls
for i := uint64(1); i <= 238; i += 30 {
recursiveDelegatecallSuccess(ctx, t, client, filename, i)
}
recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(238))
for i := uint64(239); i <= 800; i += 40 {
recursiveDelegatecallFail(ctx, t, client, filename, i)
}
}
// TestFEVMBasic does a basic fevm contract installation and invocation
func TestFEVMBasic(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
filename := "contracts/SimpleCoin.hex"
@ -60,7 +182,8 @@ func TestFEVMBasic(t *testing.T) {
// invoke the contract with owner
{
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
require.NoError(t, err)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710")
require.NoError(t, err)
@ -70,8 +193,9 @@ func TestFEVMBasic(t *testing.T) {
// invoke the contract with non owner
{
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
inputData[31]++ // change the pub address to one that has 0 balance by incrementing the last byte of the address
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
inputData[31]++ // change the pub address to one that has 0 balance by modifying the last byte of the address
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
require.NoError(t, err)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
@ -81,7 +205,7 @@ func TestFEVMBasic(t *testing.T) {
// TestFEVMETH0 tests that the ETH0 actor is in genesis
func TestFEVMETH0(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
eth0id, err := address.NewIDAddress(1001)
@ -100,7 +224,47 @@ func TestFEVMETH0(t *testing.T) {
// TestFEVMDelegateCall deploys two contracts and makes a delegate call transaction
func TestFEVMDelegateCall(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameActor := "contracts/DelegatecallActor.hex"
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
//install contract Storage
filenameStorage := "contracts/DelegatecallStorage.hex"
fromAddrStorage, storageAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
require.Equal(t, fromAddr, fromAddrStorage)
//call Contract Storage which makes a delegatecall to contract Actor
//this contract call sets the "counter" variable to 7, from default value 0
inputDataContract := inputDataFromFrom(ctx, t, client, actorAddr)
inputDataValue := inputDataFromArray([]byte{7})
inputData := append(inputDataContract, inputDataValue...)
//verify that the returned value of the call to setvars is 7
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVars(address,uint256)", inputData)
require.NoError(t, err)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
require.NoError(t, err)
require.Equal(t, result, expectedResult)
//test the value is 7 a second way by calling the getter
result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
require.NoError(t, err)
require.Equal(t, result, expectedResult)
//test the value is 0 via calling the getter on the Actor contract
result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
require.NoError(t, err)
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
require.Equal(t, result, expectedResultActor)
}
// TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert.
// the state should not have changed because of the revert
func TestFEVMDelegateCallRevert(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
@ -119,20 +283,247 @@ func TestFEVMDelegateCall(t *testing.T) {
inputData := append(inputDataContract, inputDataValue...)
//verify that the returned value of the call to setvars is 7
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVars(address,uint256)", inputData)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
require.NoError(t, err)
require.Equal(t, result, expectedResult)
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVarsRevert(address,uint256)", inputData)
require.Error(t, err)
require.Equal(t, exitcode.ExitCode(33), wait.Receipt.ExitCode)
//test the value is 7 via calling the getter
result = client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
//test the value is 0 via calling the getter and was not set to 7
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
require.NoError(t, err)
require.Equal(t, result, expectedResult)
//test the value is 0 via calling the getter on the Actor contract
result = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
require.NoError(t, err)
require.Equal(t, result, expectedResultActor)
require.Equal(t, result, expectedResult)
}
// TestFEVMSimpleRevert makes a call that is a simple revert
func TestFEVMSimpleRevert(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameStorage := "contracts/DelegatecallStorage.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//call revert
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "revert()", []byte{})
require.Equal(t, wait.Receipt.ExitCode, exitcode.ExitCode(33))
require.Error(t, err)
}
// TestFEVMSelfDestruct creates a contract that just has a self destruct feature and calls it
func TestFEVMSelfDestruct(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameStorage := "contracts/SelfDestruct.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//call destroy
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
require.NoError(t, err)
//call destroy a second time and also no error
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
require.NoError(t, err)
}
// TestFEVMTestApp deploys a fairly complex app contract and confirms it works as expected
func TestFEVMTestApp(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameStorage := "contracts/TestApp.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
inputData, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000066162636465660000000000000000000000000000000000000000000000000000") // sending string "abcdef" and int 7 - constructed using remix
require.NoError(t, err)
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "new_Test(string,uint256)", inputData)
require.NoError(t, err)
inputData, err = hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "get_Test_N(uint256)", inputData)
require.NoError(t, err)
}
// TestFEVMTestApp creates a contract that just has a self destruct feature and calls it
func TestFEVMTestConstructor(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameStorage := "contracts/Constructor.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//input = uint256{7}. set value and confirm tx success
inputData, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
require.NoError(t, err)
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "new_Test(uint256)", inputData)
require.NoError(t, err)
}
// TestFEVMAutoSelfDestruct creates a contract that just has a self destruct feature and calls it
func TestFEVMAutoSelfDestruct(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameStorage := "contracts/AutoSelfDestruct.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//call destroy
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
require.NoError(t, err)
}
// TestFEVMTestApp creates a contract that just has a self destruct feature and calls it
func TestFEVMTestSendToContract(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
require.NoError(t, err)
//install contract TestApp
filenameStorage := "contracts/SelfDestruct.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//transfer half balance to contract
sendAmount := big.Div(bal, big.NewInt(2))
client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount)
//call self destruct which should return balance
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
require.NoError(t, err)
finalBalanceMinimum := types.FromFil(uint64(99_999_999)) // 100 million FIL - 1 FIL for gas upper bounds
finalBal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
require.NoError(t, err)
require.Equal(t, true, finalBal.GreaterThan(finalBalanceMinimum))
}
// creates a contract that would fail when tx are sent to it
// on eth but on fevm it succeeds
// example failing on testnet https://goerli.etherscan.io/address/0x2ff1525e060169dbf97b9461758c8f701f107cd2
func TestFEVMTestNotPayable(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
fromAddr := client.DefaultKey.Address
t.Log("from - ", fromAddr)
//create contract A
filenameStorage := "contracts/NotPayable.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
sendAmount := big.NewInt(10_000_000)
client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount)
}
// tx to non function succeeds
func TestFEVMSendCall(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract
filenameActor := "contracts/GasSendTest.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "x()", []byte{})
require.NoError(t, err)
}
// creates a contract that would fail when tx are sent to it
// on eth but on fevm it succeeds
// example on goerli of tx failing https://goerli.etherscan.io/address/0xec037bdc9a79420985a53a49fdae3ccf8989909b
func TestFEVMSendGasLimit(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract
filenameActor := "contracts/GasLimitSend.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
//send $ to contract
//transfer 1 attoFIL to contract
sendAmount := big.MustFromString("1")
client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount)
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDataLength()", []byte{})
require.NoError(t, err)
}
// TestFEVMDelegateCall deploys the two contracts in TestFEVMDelegateCall but instead of A calling B, A calls A which should cause A to cause A in an infinite loop and should give a reasonable error
// XXX should not be fatal errors
func TestFEVMDelegateCallRecursiveFail(t *testing.T) {
//TODO change the gas limit of this invocation and confirm that the number of errors is different
//also TODO should we not have fatal error show up here?
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
filenameActor := "contracts/DelegatecallStorage.hex"
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
//any data will do for this test that fails
inputDataContract := inputDataFromFrom(ctx, t, client, actorAddr)
inputDataValue := inputDataFromArray([]byte{7})
inputData := append(inputDataContract, inputDataValue...)
//verify that the returned value of the call to setvars is 7
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "setVarsSelf(address,uint256)", inputData)
require.Error(t, err)
require.Equal(t, exitcode.SysErrorIllegalArgument, wait.Receipt.ExitCode)
//assert no fatal errors but still there are errors::
errorAny := "fatal error"
require.NotContains(t, err.Error(), errorAny)
}
// XXX Currently fails as self destruct has a bug
// TestFEVMTestSendValueThroughContracts creates A and B contract and exchanges value
// and self destructs and accounts for value sent
func TestFEVMTestSendValueThroughContractsAndDestroy(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
fromAddr := client.DefaultKey.Address
t.Log("from - ", fromAddr)
//create contract A
filenameStorage := "contracts/ValueSender.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//create contract B
ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "createB()", []byte{})
require.NoError(t, err)
ethAddr, err := ethtypes.CastEthAddress(ret[12:])
require.NoError(t, err)
contractBAddress, err := ethAddr.ToFilecoinAddress()
require.NoError(t, err)
t.Log("contractBAddress - ", contractBAddress)
//self destruct contract B
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractBAddress, "selfDestruct()", []byte{})
require.NoError(t, err)
}
func TestEVMRpcDisable(t *testing.T) {
@ -144,7 +535,7 @@ func TestEVMRpcDisable(t *testing.T) {
// TestFEVMRecursiveFuncCall deploys a contract and makes a recursive function calls
func TestFEVMRecursiveFuncCall(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor
@ -155,7 +546,6 @@ func TestFEVMRecursiveFuncCall(t *testing.T) {
return func(t *testing.T) {
inputData := make([]byte, 32)
binary.BigEndian.PutUint64(inputData[24:], uint64(n))
client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256)", inputData, ex)
}
}
@ -170,7 +560,7 @@ func TestFEVMRecursiveFuncCall(t *testing.T) {
// TestFEVMRecursiveActorCall deploys a contract and makes a recursive actor calls
func TestFEVMRecursiveActorCall(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
//install contract Actor

View File

@ -7,8 +7,11 @@ import (
"encoding/hex"
"fmt"
"os"
"testing"
"time"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
"github.com/multiformats/go-varint"
"github.com/stretchr/testify/require"
cbg "github.com/whyrusleeping/cbor-gen"
@ -101,13 +104,13 @@ func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string
return fromAddr, idAddr
}
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) *api.MsgLookup {
require := require.New(e.t)
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) {
params := append(selector, inputData...)
var buffer bytes.Buffer
err := cbg.WriteByteArray(&buffer, params)
require.NoError(err)
if err != nil {
return nil, err
}
params = buffer.Bytes()
msg := &types.Message{
@ -121,13 +124,17 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target
e.t.Log("sending invoke message")
smsg, err := e.MpoolPushMessage(ctx, msg, nil)
require.NoError(err)
if err != nil {
return nil, err
}
e.t.Log("waiting for message to execute")
wait, err := e.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
require.NoError(err)
if err != nil {
return nil, err
}
return wait
return wait, nil
}
// LoadEvents loads all events in an event AMT.
@ -237,18 +244,25 @@ func (e *EVM) ComputeContractAddress(deployer ethtypes.EthAddress, nonce uint64)
return *(*ethtypes.EthAddress)(hasher.Sum(nil)[12:])
}
func (e *EVM) InvokeContractByFuncName(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte) []byte {
func (e *EVM) InvokeContractByFuncName(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte) ([]byte, *api.MsgLookup, error) {
entryPoint := CalcFuncSignature(funcSignature)
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.True(e.t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed: %d", wait.Receipt.ExitCode)
wait, err := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
if err != nil {
return nil, wait, err
}
if !wait.Receipt.ExitCode.IsSuccess() {
return nil, wait, fmt.Errorf("contract execution failed - %v", wait.Receipt.ExitCode)
}
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
require.NoError(e.t, err)
return result
if err != nil {
return nil, wait, err
}
return result, wait, nil
}
func (e *EVM) InvokeContractByFuncNameExpectExit(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte, exit exitcode.ExitCode) {
entryPoint := CalcFuncSignature(funcSignature)
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
wait, _ := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.Equal(e.t, exit, wait.Receipt.ExitCode)
}
@ -310,3 +324,40 @@ func removeLeadingZeros(data []byte) []byte {
}
return data[firstNonZeroIndex:]
}
func SetupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *TestFullNode) {
//make all logs extra quiet for fevm tests
lvl, err := logging.LevelFromString("error")
if err != nil {
panic(err)
}
logging.SetAllLoggers(lvl)
blockTime := 100 * time.Millisecond
client, _, ens := EnsembleMinimal(t, MockProofs(), ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
// require that the initial balance is 100 million FIL in setup
// this way other tests can count on this initial wallet balance
fromAddr := client.DefaultKey.Address
bal, err := client.WalletBalance(ctx, fromAddr)
require.NoError(t, err)
originalBalance := types.FromFil(uint64(100_000_000)) // 100 million FIL
require.Equal(t, originalBalance, bal)
return ctx, cancel, client
}
func (e *EVM) TransferValueOrFail(ctx context.Context, fromAddr address.Address, toAddr address.Address, sendAmount big.Int) {
sendMsg := &types.Message{
From: fromAddr,
To: toAddr,
Value: sendAmount,
}
signedMsg, err := e.MpoolPushMessage(ctx, sendMsg, nil)
require.NoError(e.t, err)
mLookup, err := e.StateWaitMsg(ctx, signedMsg.Cid(), 3, api.LookbackNoLimit, true)
require.NoError(e.t, err)
require.Equal(e.t, exitcode.Ok, mLookup.Receipt.ExitCode)
}