package vm import ( "bytes" "errors" "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/common" "github.com/harmony-one/harmony/internal/params" stakingTypes "github.com/harmony-one/harmony/staking/types" ) type writeCapablePrecompileTest struct { input, expected []byte name string expectedError error p *WriteCapablePrecompiledContract } func CollectRewardsFn() CollectRewardsFunc { return func(db StateDB, rosettaTracer RosettaTracer, collectRewards *stakingTypes.CollectRewards) error { return nil } } func DelegateFn() DelegateFunc { return func(db StateDB, rosettaTracer RosettaTracer, delegate *stakingTypes.Delegate) error { return nil } } func UndelegateFn() UndelegateFunc { return func(db StateDB, rosettaTracer RosettaTracer, undelegate *stakingTypes.Undelegate) error { return nil } } func CreateValidatorFn() CreateValidatorFunc { return func(db StateDB, rosettaTracer RosettaTracer, createValidator *stakingTypes.CreateValidator) error { return nil } } func EditValidatorFn() EditValidatorFunc { return func(db StateDB, rosettaTracer RosettaTracer, editValidator *stakingTypes.EditValidator) error { return nil } } //func MigrateDelegationsFn() MigrateDelegationsFunc { // return func(db StateDB, migrationMsg *stakingTypes.MigrationMsg) ([]interface{}, error) { // return nil, nil // } //} func CalculateMigrationGasFn() CalculateMigrationGasFunc { return func(db StateDB, migrationMsg *stakingTypes.MigrationMsg, homestead bool, istanbul bool) (uint64, error) { return 0, nil } } func testStakingPrecompile(test writeCapablePrecompileTest, t *testing.T) { var env = NewEVM(Context{CollectRewards: CollectRewardsFn(), Delegate: DelegateFn(), Undelegate: UndelegateFn(), CreateValidator: CreateValidatorFn(), EditValidator: EditValidatorFn(), ShardID: 0, //MigrateDelegations: MigrateDelegationsFn(), CalculateMigrationGas: CalculateMigrationGasFn(), }, nil, params.TestChainConfig, Config{}) // use required gas to avoid out of gas errors p := &stakingPrecompile{} t.Run(fmt.Sprintf("%s", test.name), func(t *testing.T) { contract := NewContract(AccountRef(common.HexToAddress("1337")), AccountRef(common.HexToAddress("1338")), new(big.Int), 0) gas, err := p.RequiredGas(env, contract, test.input) if err != nil { t.Error(err) } contract.Gas = gas if res, err := RunWriteCapablePrecompiledContract(p, env, contract, test.input, false); err != nil { if test.expectedError != nil { if test.expectedError.Error() != err.Error() { t.Errorf("Expected error %v, got %v", test.expectedError, err) } } else { t.Error(err) } } else { if test.expectedError != nil { t.Errorf("Expected an error %v but instead got result %v", test.expectedError, res) } if bytes.Compare(res, test.expected) != 0 { t.Errorf("Expected %v, got %v", test.expected, res) } } }) } func TestStakingPrecompiles(t *testing.T) { for _, test := range StakingPrecompileTests { testStakingPrecompile(test, t) } } func TestWriteCapablePrecompilesReadOnly(t *testing.T) { p := &stakingPrecompile{} expectedError := errWriteProtection res, err := RunWriteCapablePrecompiledContract(p, nil, nil, []byte{}, true) if err != nil { if err.Error() != expectedError.Error() { t.Errorf("Expected error %v, got %v", expectedError, err) } } else { t.Errorf("Expected an error %v but instead got result %v", expectedError, res) } } var StakingPrecompileTests = []writeCapablePrecompileTest{ { input: []byte{109, 107, 47, 120}, expectedError: errors.New("no method with id: 0x6d6b2f78"), name: "badStakingKind", }, { input: []byte{0, 0}, expectedError: errors.New("data too short (2 bytes) for abi method lookup"), name: "malformedInput", }, { input: []byte{109, 107, 47, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55}, expected: nil, name: "collectRewardsSuccess", }, { input: []byte{109, 107, 47, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56}, expectedError: errors.New("[StakingPrecompile] Address mismatch, expected 0x0000000000000000000000000000000000001337 have 0x0000000000000000000000000000000000001338"), name: "collectRewardsAddressMismatch", }, { input: []byte{109, 107, 47, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19}, expectedError: errors.New("abi: cannot marshal in to go type: length insufficient 31 require 32"), name: "collectRewardsInvalidABI", }, { input: []byte{81, 11, 17, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0, 0}, expected: nil, name: "delegateSuccess", }, { input: []byte{81, 11, 17, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0}, expectedError: errors.New("abi: cannot marshal in to go type: length insufficient 95 require 96"), name: "delegateInvalidABI", }, { input: []byte{81, 11, 17, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0, 0}, expectedError: errors.New("[StakingPrecompile] Address mismatch, expected 0x0000000000000000000000000000000000001337 have 0x0000000000000000000000000000000000001338"), name: "delegateAddressMismatch", }, { input: []byte{189, 168, 192, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0, 0}, expected: nil, name: "undelegateSuccess", }, { input: []byte{189, 168, 192, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0}, expectedError: errors.New("abi: cannot marshal in to go type: length insufficient 95 require 96"), name: "undelegateInvalidABI", }, { input: []byte{189, 168, 192, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0, 0}, expectedError: errors.New("[StakingPrecompile] Address mismatch, expected 0x0000000000000000000000000000000000001337 have 0x0000000000000000000000000000000000001338"), name: "undelegateAddressMismatch", }, { input: []byte{189, 168, 192, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 107, 199, 94, 45, 99, 16, 0, 0}, expectedError: errors.New("[StakingPrecompile] Address mismatch, expected 0x0000000000000000000000000000000000001337 have 0x0000000000000000000000000000000000001338"), name: "undelegateAddressMismatch", }, //{ // input: []byte{42, 5, 187, 113}, // expectedError: errors.New("abi: attempting to unmarshall an empty string while arguments are expected"), // name: "yesMethodNoData", //}, //{ // input: []byte{0, 0}, // expectedError: errors.New("data too short (2 bytes) for abi method lookup"), // name: "malformedInput", //}, //{ // input: []byte{42, 5, 187, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56}, // expected: nil, // name: "migrationSuccess", //}, //{ // input: []byte{42, 5, 187, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55}, // expectedError: errors.New("[StakingPrecompile] Address mismatch, expected 0x0000000000000000000000000000000000001337 have 0x0000000000000000000000000000000000001338"), // name: "migrationAddressMismatch", //}, //{ // input: []byte{42, 6, 187, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55}, // expectedError: errors.New("no method with id: 0x2a06bb71"), // name: "migrationNoMatchingMethod", //}, //{ // input: []byte{42, 5, 187, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19}, // expectedError: errors.New("abi: cannot marshal in to go type: length insufficient 63 require 64"), // name: "migrationAddressMismatch", //}, }