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:
parent
a38e63998e
commit
9060c474da
1
itests/contracts/AutoSelfDestruct.hex
Normal file
1
itests/contracts/AutoSelfDestruct.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b5061001f61002460201b60201c565b61003d565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60848061004b6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea26469706673582212208d48a69a112633756d84552847610df29b02ac89dd39e4e295066e99a45e809664736f6c63430008110033
|
11
itests/contracts/AutoSelfDestruct.sol
Normal file
11
itests/contracts/AutoSelfDestruct.sol
Normal 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));
|
||||
}
|
||||
}
|
1
itests/contracts/Constructor.hex
Normal file
1
itests/contracts/Constructor.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b506103ca806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806358f5ebb614610030575b600080fd5b61004a60048036038101906100459190610123565b610060565b6040516100579190610191565b60405180910390f35b60008082604051610070906100db565b61007a91906101bb565b604051809103906000f080158015610096573d6000803e3d6000fd5b5090507f3a5c468996b00310e3e82919e3af9cce21d49c40c39a2627a9f946e1a54d886232846040516100ca9291906101d6565b60405180910390a180915050919050565b6101958061020083390190565b600080fd5b6000819050919050565b610100816100ed565b811461010b57600080fd5b50565b60008135905061011d816100f7565b92915050565b600060208284031215610139576101386100e8565b5b60006101478482850161010e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017b82610150565b9050919050565b61018b81610170565b82525050565b60006020820190506101a66000830184610182565b92915050565b6101b5816100ed565b82525050565b60006020820190506101d060008301846101ac565b92915050565b60006040820190506101eb6000830185610182565b6101f860208301846101ac565b939250505056fe608060405234801561001057600080fd5b506040516101953803806101958339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b60e0806100b56000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80638381f58a146037578063eeb4e367146051575b600080fd5b603d606b565b604051604891906091565b60405180910390f35b60576071565b604051606291906091565b60405180910390f35b60005481565b60008054905090565b6000819050919050565b608b81607a565b82525050565b600060208201905060a460008301846084565b9291505056fea2646970667358221220451c388f24a935fc5f5eef536207cbd982254ac8521d49937bb10e5079e3924164736f6c63430008110033a264697066735822122027da159d84a9bdcd5aff5755c4602f7099db638f7a95d715c76454c99511146f64736f6c63430008110033
|
29
itests/contracts/Constructor.sol
Normal file
29
itests/contracts/Constructor.sol
Normal 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;
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
608060405234801561001057600080fd5b50610477806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780638ada066e14610064578063d1e0f3081461008f575b600080fd5b34801561004557600080fd5b5061004e6100bf565b60405161005b919061022c565b60405180910390f35b34801561007057600080fd5b506100796100c5565b604051610086919061022c565b60405180910390f35b6100a960048036038101906100a491906102d6565b6100ce565b6040516100b6919061022c565b60405180910390f35b60005481565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16836040516024016100f9919061022c565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101839190610387565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b5050905080610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101fe90610421565b60405180910390fd5b60005491505092915050565b6000819050919050565b61022681610213565b82525050565b6000602082019050610241600083018461021d565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102778261024c565b9050919050565b6102878161026c565b811461029257600080fd5b50565b6000813590506102a48161027e565b92915050565b6102b381610213565b81146102be57600080fd5b50565b6000813590506102d0816102aa565b92915050565b600080604083850312156102ed576102ec610247565b5b60006102fb85828601610295565b925050602061030c858286016102c1565b9150509250929050565b600081519050919050565b600081905092915050565b60005b8381101561034a57808201518184015260208101905061032f565b60008484015250505050565b600061036182610316565b61036b8185610321565b935061037b81856020860161032c565b80840191505092915050565b60006103938284610356565b915081905092915050565b600082825260208201905092915050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b600061040b60228361039e565b9150610416826103af565b604082019050919050565b6000602082019050818103600083015261043a816103fe565b905091905056fea26469706673582212203663909b8221e9b87047be99420c00339af1430c085260df209b909ed8e0f05164736f6c63430008110033
|
||||
608060405234801561001057600080fd5b5061087e806100206000396000f3fe6080604052600436106100555760003560e01c80630712ede21461005a57806361bc221a1461008a5780637da3c3ab146100b55780638ada066e146100cc578063bed56f47146100f7578063d1e0f30814610127575b600080fd5b610074600480360381019061006f919061060f565b610157565b604051610081919061065e565b60405180910390f35b34801561009657600080fd5b5061009f610298565b6040516100ac919061065e565b60405180910390f35b3480156100c157600080fd5b506100ca61029e565b005b3480156100d857600080fd5b506100e16102e1565b6040516100ee919061065e565b60405180910390f35b610111600480360381019061010c919061060f565b6102ea565b60405161011e919061065e565b60405180910390f35b610141600480360381019061013c919061060f565b610431565b60405161014e919061065e565b60405180910390f35b6000808373ffffffffffffffffffffffffffffffffffffffff1683604051602401610182919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161020c91906106ea565b600060405180830381855af49150503d8060008114610247576040519150601f19603f3d011682016040523d82523d6000602084013e61024c565b606091505b505090506000610291576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102889061075e565b60405180910390fd5b5092915050565b60005481565b60006102df576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d69061075e565b60405180910390fd5b565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16848460405160240161031792919061078d565b6040516020818303038152906040527fbed56f47000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516103a191906106ea565b600060405180830381855af49150503d80600081146103dc576040519150601f19603f3d011682016040523d82523d6000602084013e6103e1565b606091505b5050905080610425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161041c90610828565b60405180910390fd5b60005491505092915050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405160240161045c919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104e691906106ea565b600060405180830381855af49150503d8060008114610521576040519150601f19603f3d011682016040523d82523d6000602084013e610526565b606091505b505090508061056a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056190610828565b60405180910390fd5b60005491505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a68261057b565b9050919050565b6105b68161059b565b81146105c157600080fd5b50565b6000813590506105d3816105ad565b92915050565b6000819050919050565b6105ec816105d9565b81146105f757600080fd5b50565b600081359050610609816105e3565b92915050565b6000806040838503121561062657610625610576565b5b6000610634858286016105c4565b9250506020610645858286016105fa565b9150509250929050565b610658816105d9565b82525050565b6000602082019050610673600083018461064f565b92915050565b600081519050919050565b600081905092915050565b60005b838110156106ad578082015181840152602081019050610692565b60008484015250505050565b60006106c482610679565b6106ce8185610684565b93506106de81856020860161068f565b80840191505092915050565b60006106f682846106b9565b915081905092915050565b600082825260208201905092915050565b7f696e74656e74696f6e616c6c79207468726f77696e67206572726f7200000000600082015250565b6000610748601c83610701565b915061075382610712565b602082019050919050565b600060208201905081810360008301526107778161073b565b9050919050565b6107878161059b565b82525050565b60006040820190506107a2600083018561077e565b6107af602083018461064f565b9392505050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b6000610812602283610701565b915061081d826107b6565b604082019050919050565b6000602082019050818103600083015261084181610805565b905091905056fea2646970667358221220b2a3ae7e2a9ffc78e3e2a7aadb2885435c5e51aa9d3f07372a0dffb6238aa1db64736f6c63430008110033
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
1
itests/contracts/GasLimitSend.hex
Normal file
1
itests/contracts/GasLimitSend.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b5061027c806100206000396000f3fe6080604052600436106100385760003560e01c80630bc07a88146100435780633da767881461005a578063f0ba84401461008557610039565b5b6100416100c2565b005b34801561004f57600080fd5b506100586100c2565b005b34801561006657600080fd5b5061006f61010d565b60405161007c9190610156565b60405180910390f35b34801561009157600080fd5b506100ac60048036038101906100a791906101a2565b610119565b6040516100b99190610156565b60405180910390f35b60005b606481101561010a5760008190806001815401808255809150506001900390600052602060002001600090919091909150558080610102906101fe565b9150506100c5565b50565b60008080549050905090565b6000818154811061012957600080fd5b906000526020600020016000915090505481565b6000819050919050565b6101508161013d565b82525050565b600060208201905061016b6000830184610147565b92915050565b600080fd5b61017f8161013d565b811461018a57600080fd5b50565b60008135905061019c81610176565b92915050565b6000602082840312156101b8576101b7610171565b5b60006101c68482850161018d565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006102098261013d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361023b5761023a6101cf565b5b60018201905091905056fea2646970667358221220c56d78e0c60a01681eee1b76c95e7b214d16a512c944e31cfee71eb727c1e44064736f6c63430008110033
|
34
itests/contracts/GasLimitSend.sol
Normal file
34
itests/contracts/GasLimitSend.sol
Normal 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;
|
||||
}
|
||||
}
|
1
itests/contracts/GasSendTest.hex
Normal file
1
itests/contracts/GasSendTest.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220c0f2da1b01178b54afba1ddf14f30307a03cdb66f61b4e1dc342079561db009064736f6c63430008110033
|
9
itests/contracts/GasSendTest.sol
Normal file
9
itests/contracts/GasSendTest.sol
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
contract GasLimitTestReceiver {
|
||||
function x() public returns (uint256){
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
1
itests/contracts/NotPayable.hex
Normal file
1
itests/contracts/NotPayable.hex
Normal file
@ -0,0 +1 @@
|
||||
6080604052348015600f57600080fd5b50604780601d6000396000f3fe6080604052348015600f57600080fd5b00fea26469706673582212200cd38951eddebe3692dc8921afb65a04fbe64e10d5e261806330156459bf227264736f6c63430008110033
|
7
itests/contracts/NotPayable.sol
Normal file
7
itests/contracts/NotPayable.sol
Normal 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 {}
|
||||
}
|
1
itests/contracts/Recursive.hex
Normal file
1
itests/contracts/Recursive.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b506102d9806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063032cec451461005c57806372536f3c1461007a57806399fdb86e14610098578063d2aac3ea146100b6578063ec49254c146100d4575b600080fd5b610064610104565b60405161007191906101c7565b60405180910390f35b610082610115565b60405161008f91906101c7565b60405180910390f35b6100a0610126565b6040516100ad91906101c7565b60405180910390f35b6100be610137565b6040516100cb91906101c7565b60405180910390f35b6100ee60048036038101906100e99190610213565b610148565b6040516100fb91906101c7565b60405180910390f35b60006101106001610148565b905090565b6000610121600a610148565b905090565b60006101326002610148565b905090565b60006101436000610148565b905090565b6000808211156101a5577f3110e0ccd510fcbb471c933ad12161c459e8735b5bde2eea61a659c2e2f0a3cc8260405161018191906101c7565b60405180910390a161019e600183610199919061026f565b610148565b90506101a9565b8190505b919050565b6000819050919050565b6101c1816101ae565b82525050565b60006020820190506101dc60008301846101b8565b92915050565b600080fd5b6101f0816101ae565b81146101fb57600080fd5b50565b60008135905061020d816101e7565b92915050565b600060208284031215610229576102286101e2565b5b6000610237848285016101fe565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061027a826101ae565b9150610285836101ae565b925082820390508181111561029d5761029c610240565b5b9291505056fea26469706673582212206178e15eb87e2f766b94ec09a6a860878c93d72a31de225e1684da1755f917c764736f6c63430008110033
|
26
itests/contracts/Recursive.sol
Normal file
26
itests/contracts/Recursive.sol
Normal 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;
|
||||
}
|
||||
}
|
1
itests/contracts/RecursiveDelegeatecall.hex
Normal file
1
itests/contracts/RecursiveDelegeatecall.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b50610459806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633af3f24f1461003b578063ec49254c14610059575b600080fd5b610043610089565b6040516100509190610221565b60405180910390f35b610073600480360381019061006e919061026d565b61008f565b6040516100809190610221565b60405180910390f35b60005481565b60007faab69767807d0ab32f0099452739da31b76ecd3e8694bb49898829c8bf9d063582306040516100c29291906102db565b60405180910390a160016000808282546100dc9190610333565b9250508190555060018211156101ff576001826100f99190610367565b91506000803073ffffffffffffffffffffffffffffffffffffffff16846040516024016101269190610221565b6040516020818303038152906040527fec49254c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101b0919061040c565b600060405180830381855af49150503d80600081146101eb576040519150601f19603f3d011682016040523d82523d6000602084013e6101f0565b606091505b50915091508392505050610203565b8190505b919050565b6000819050919050565b61021b81610208565b82525050565b60006020820190506102366000830184610212565b92915050565b600080fd5b61024a81610208565b811461025557600080fd5b50565b60008135905061026781610241565b92915050565b6000602082840312156102835761028261023c565b5b600061029184828501610258565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102c58261029a565b9050919050565b6102d5816102ba565b82525050565b60006040820190506102f06000830185610212565b6102fd60208301846102cc565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061033e82610208565b915061034983610208565b925082820190508082111561036157610360610304565b5b92915050565b600061037282610208565b915061037d83610208565b925082820390508181111561039557610394610304565b5b92915050565b600081519050919050565b600081905092915050565b60005b838110156103cf5780820151818401526020810190506103b4565b60008484015250505050565b60006103e68261039b565b6103f081856103a6565b93506104008185602086016103b1565b80840191505092915050565b600061041882846103db565b91508190509291505056fea2646970667358221220e70fbbfaccd3fbb084623d6d06895fba1abc5fefc181215b56ab1e43db79c7fb64736f6c63430008110033
|
21
itests/contracts/RecursiveDelegeatecall.sol
Normal file
21
itests/contracts/RecursiveDelegeatecall.sol
Normal 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;
|
||||
}
|
||||
}
|
1
itests/contracts/SelfDestruct.hex
Normal file
1
itests/contracts/SelfDestruct.hex
Normal file
@ -0,0 +1 @@
|
||||
6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220d4aa109d42268586e7ce4f0fafb0ebbd04c412c6c7e8c387b009a08ecdff864264736f6c63430008110033
|
8
itests/contracts/SelfDestruct.sol
Normal file
8
itests/contracts/SelfDestruct.sol
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity >=0.8.17;
|
||||
|
||||
contract SelfDestruct {
|
||||
function destroy() public {
|
||||
selfdestruct(payable(msg.sender));
|
||||
}
|
||||
}
|
1
itests/contracts/TestApp.hex
Normal file
1
itests/contracts/TestApp.hex
Normal file
File diff suppressed because one or more lines are too long
211
itests/contracts/TestApp.sol
Normal file
211
itests/contracts/TestApp.sol
Normal 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
|
||||
});
|
||||
}
|
||||
}
|
1
itests/contracts/ValueSender.hex
Normal file
1
itests/contracts/ValueSender.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b506106dc806100206000396000f3fe60806040526004361061002d5760003560e01c8063dbdc275d14610072578063fd75295a1461009d5761006d565b3661006d577f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd679308333460405161006392919061020f565b60405180910390a1005b600080fd5b34801561007e57600080fd5b506100876100b9565b6040516100949190610238565b60405180910390f35b6100b760048036038101906100b29190610296565b610125565b005b6000806040516100c8906101a8565b604051809103906000f0801580156100e4573d6000803e3d6000fd5b5090507f8db3b20eed31d927a4f613b5c11765212e129cf726d025649650665569ea683b816040516101169190610238565b60405180910390a18091505090565b7f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd6793088134604051610156929190610322565b60405180910390a18073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156101a4573d6000803e3d6000fd5b5050565b61035b8061034c83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e0826101b5565b9050919050565b6101f0816101d5565b82525050565b6000819050919050565b610209816101f6565b82525050565b600060408201905061022460008301856101e7565b6102316020830184610200565b9392505050565b600060208201905061024d60008301846101e7565b92915050565b600080fd5b6000610263826101b5565b9050919050565b61027381610258565b811461027e57600080fd5b50565b6000813590506102908161026a565b92915050565b6000602082840312156102ac576102ab610253565b5b60006102ba84828501610281565b91505092915050565b6000819050919050565b60006102e86102e36102de846101b5565b6102c3565b6101b5565b9050919050565b60006102fa826102cd565b9050919050565b600061030c826102ef565b9050919050565b61031c81610301565b82525050565b60006040820190506103376000830185610313565b6103446020830184610200565b939250505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102fb806100606000396000f3fe60806040526004361061002d5760003560e01c806337cb6570146100725780639cb8a26a1461007c5761006d565b3661006d577fe1494f56a1ccfd8c7361f2ca5b8fd2b1a2fe11773821ac29534f09f4a0637d603334604051610063929190610214565b60405180910390a1005b600080fd5b61007a610093565b005b34801561008857600080fd5b50610091610155565b005b7f76cff203b0794a9e9013657ecb172f2d6e8de5941fd11a6bfbc0fb6014a5f07960008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16476040516100e492919061029c565b60405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610152573d6000803e3d6000fd5b50565b7f1cbd47e7b0f55dc1a45ba8ebada53eaa1712b3e3e86f49a12c008ff22334569060405160405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e5826101ba565b9050919050565b6101f5816101da565b82525050565b6000819050919050565b61020e816101fb565b82525050565b600060408201905061022960008301856101ec565b6102366020830184610205565b9392505050565b6000819050919050565b600061026261025d610258846101ba565b61023d565b6101ba565b9050919050565b600061027482610247565b9050919050565b600061028682610269565b9050919050565b6102968161027b565b82525050565b60006040820190506102b1600083018561028d565b6102be6020830184610205565b939250505056fea2646970667358221220bdf21908b1c91973a8440fe81130e0077cf83c8f8e9a053d8a0c3063391aa40764736f6c63430008110033a26469706673582212202e514fe078dfcf4f1142a088c57cfa71ada74d72ee0cc4a46b7e1141cdbaeeed64736f6c63430008110033
|
54
itests/contracts/ValueSender.sol
Normal file
54
itests/contracts/ValueSender.sol
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user