Skip to content
This repository has been archived by the owner before Nov 9, 2022. It is now read-only.
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
pragma solidity ^0.6.2;
import "../lib/ds-test/src/test.sol";
import "./vyper_setup.sol";
import "../deposit_contract.sol";
contract DepositContractTest is DSTest {
DepositContract depositContract_sol;
DepositContract depositContract_vyp;
uint64 constant GWEI = 1000000000;
function setUp() public {
VyperSetup vyperSetup = new VyperSetup();
depositContract_vyp = DepositContract(vyperSetup.deployDeposit());
depositContract_sol = new DepositContract();
}
// --- SUCCESS TESTS ---
// Tests initilized storage values, comparing vyper and solidity
function test_empty_root() public {
bytes32 zHash = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 zHashN = zHash;
for (uint i = 0; i <= 31; i++) {
zHashN = sha256(abi.encodePacked(zHashN, zHashN));
}
assertEq(sha256(abi.encodePacked(zHashN, zHash)), depositContract_vyp.get_deposit_root());
assertEq(depositContract_sol.get_deposit_root(), depositContract_vyp.get_deposit_root());
}
// Generates 16 random deposits, insert them in both vyper and solidity version and compare get_deposit_root after each insertion
function test_16_deposits(bytes32[16] memory pubkey_one, bytes16[16] memory pubkey_two, bytes32[16] memory _withdrawal_credentials,
bytes32[16] memory sig_one, bytes32[16] memory sig_two, bytes32[16] memory sig_three, uint32[16] memory amount) public {
uint j;
for (uint i = 0; i < 16; i++) {
// as of dcaa774, the solidity version is more restrictive than vyper and requires deposits to be divisible by GWEI
uint64 gweiamount = amount[i] * GWEI;
if (1 ether <= gweiamount) {
j++;
deposit_in(depositContract_sol, pubkey_one[i], pubkey_two[i], _withdrawal_credentials[i], sig_one[i], sig_two[i], sig_three[i], gweiamount);
deposit_in(depositContract_vyp, pubkey_one[i], pubkey_two[i], _withdrawal_credentials[i], sig_one[i], sig_two[i], sig_three[i], gweiamount);
assertEq(depositContract_sol.get_deposit_root(), depositContract_vyp.get_deposit_root());
assertEq(keccak256(abi.encodePacked(depositContract_sol.get_deposit_count())), keccak256(abi.encodePacked(depositContract_vyp.get_deposit_count())));
assertEq(keccak256(abi.encodePacked(depositContract_sol.get_deposit_count())), keccak256(to_little_endian_64(uint64(j))));
}
}
}
// The solidity contract fails when given a deposit which is not divisible by GWEI
function testFail_deposit_not_divisible_by_gwei(bytes32 pubkey_one, bytes16 pubkey_two, bytes32 _withdrawal_credentials,
bytes32 sig_one, bytes32 sig_two, bytes32 sig_three) public {
deposit_in(depositContract_sol, pubkey_one, pubkey_two, _withdrawal_credentials, sig_one, sig_two, sig_three, 1 ether + 1);
}
// --- FAILURE TESTS ---
// if the node is given randomly instead of as the ssz root, the chances of success are so unlikely that we can assert it to be false
function testFail_malformed_node_vyp(bytes32 pubkey_one, bytes16 pubkey_two, bytes32 _withdrawal_credentials, bytes32 sig_one,
bytes32 sig_two, bytes32 sig_three, uint64 amount, bytes32 node) public {
bytes memory pubkey = abi.encodePacked(pubkey_one, pubkey_two);
bytes memory withdrawal_credentials = abi.encodePacked(_withdrawal_credentials); //I wish just recasting to `bytes` would work..
bytes memory signature = abi.encodePacked(sig_one, sig_two, sig_three);
depositContract_vyp.deposit{value: amount}(pubkey, withdrawal_credentials, signature, node);
}
// If the node is taken randomly instead of as the ssz root, the chances of success are so unlikely that we can assert it to be false
function testFail_malformed_node_sol(bytes32 pubkey_one, bytes16 pubkey_two, bytes32 _withdrawal_credentials, bytes32 sig_one,
bytes32 sig_two, bytes32 sig_three, uint64 amount, bytes32 node) public {
bytes memory pubkey = abi.encodePacked(pubkey_one, pubkey_two);
bytes memory withdrawal_credentials = abi.encodePacked(_withdrawal_credentials);
bytes memory signature = abi.encodePacked(sig_one, sig_two, sig_three);
depositContract_sol.deposit{value: amount}(pubkey, withdrawal_credentials, signature, node);
}
// if bytes lengths are wrong, the call will fail
function testFail_malformed_calldata_vyp(bytes memory pubkey, bytes memory withdrawal_credentials, bytes memory signature, uint64 amount) public {
if (amount >= 1000000000000000000) {
if (!(pubkey.length == 48 && withdrawal_credentials.length == 32 && signature.length == 96)) {
depositContract_vyp.deposit{value: amount}(pubkey, withdrawal_credentials, signature,
encode_node(pubkey, withdrawal_credentials, signature, to_little_endian_64(amount / GWEI))
);
} else { revert(); }
} else { revert(); }
}
function testFail_malformed_calldata_sol(bytes memory pubkey, bytes memory withdrawal_credentials, bytes memory signature, uint64 amount) public {
if (amount >= 1000000000000000000) {
if (!(pubkey.length == 48 && withdrawal_credentials.length == 32 && signature.length == 96)) {
depositContract_sol.deposit{value: amount}(pubkey, withdrawal_credentials, signature,
encode_node(pubkey, withdrawal_credentials, signature, to_little_endian_64(amount / GWEI))
);
} else { revert(); }
} else { revert(); }
}
// --- HELPER FUNCTIONS ---
function deposit_in(DepositContract depositContract, bytes32 pubkey_one, bytes16 pubkey_two, bytes32 _withdrawal_credentials, bytes32 sig_one, bytes32 sig_two, bytes32 sig_three, uint64 amount) public {
bytes memory pubkey = abi.encodePacked(pubkey_one, pubkey_two);
bytes memory withdrawal_credentials = abi.encodePacked(_withdrawal_credentials);
bytes memory signature = abi.encodePacked(sig_one, sig_two, sig_three);
bytes32 node = encode_node(pubkey, withdrawal_credentials, signature, to_little_endian_64(amount / GWEI));
depositContract.deposit{value: amount}(pubkey, withdrawal_credentials, signature, node);
}
function slice(bytes memory a, uint32 offset, uint32 size) pure internal returns (bytes memory result) {
result = new bytes(size);
for (uint i = 0; i < size; i++) {
result[i] = a[offset + i];
}
}
function encode_node(bytes memory pubkey, bytes memory withdrawal_credentials, bytes memory signature, bytes memory amount) public pure returns (bytes32) {
bytes16 zero_bytes16;
bytes24 zero_bytes24;
bytes32 zero_bytes32;
bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, zero_bytes16));
bytes32 signature_root = sha256(abi.encodePacked(
sha256(abi.encodePacked(slice(signature, 0, 64))),
sha256(abi.encodePacked(slice(signature, 64, 32), zero_bytes32))
));
return sha256(abi.encodePacked(
sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),
sha256(abi.encodePacked(amount, zero_bytes24, signature_root))
));
}
function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) {
ret = new bytes(8);
ret[0] = bytes1(uint8(value & 0xff));
ret[1] = bytes1(uint8((value >> 8) & 0xff));
ret[2] = bytes1(uint8((value >> 16) & 0xff));
ret[3] = bytes1(uint8((value >> 24) & 0xff));
ret[4] = bytes1(uint8((value >> 32) & 0xff));
ret[5] = bytes1(uint8((value >> 40) & 0xff));
ret[6] = bytes1(uint8((value >> 48) & 0xff));
ret[7] = bytes1(uint8((value >> 56) & 0xff));
}
}