github.com/xfond/eth-implementation@v1.8.9-0.20180514135602-f6bc65fc6811/signer/core/abihelper_test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	"io/ioutil"
    25  	"math/big"
    26  	"reflect"
    27  
    28  	"github.com/ethereum/go-ethereum/accounts/abi"
    29  	"github.com/ethereum/go-ethereum/common"
    30  )
    31  
    32  func verify(t *testing.T, jsondata, calldata string, exp []interface{}) {
    33  
    34  	abispec, err := abi.JSON(strings.NewReader(jsondata))
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	cd := common.Hex2Bytes(calldata)
    39  	sigdata, argdata := cd[:4], cd[4:]
    40  	method, err := abispec.MethodById(sigdata)
    41  
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	data, err := method.Inputs.UnpackValues(argdata)
    47  
    48  	if len(data) != len(exp) {
    49  		t.Fatalf("Mismatched length, expected %d, got %d", len(exp), len(data))
    50  	}
    51  	for i, elem := range data {
    52  		if !reflect.DeepEqual(elem, exp[i]) {
    53  			t.Fatalf("Unpack error, arg %d, got %v, want %v", i, elem, exp[i])
    54  		}
    55  	}
    56  }
    57  func TestNewUnpacker(t *testing.T) {
    58  	type unpackTest struct {
    59  		jsondata string
    60  		calldata string
    61  		exp      []interface{}
    62  	}
    63  	testcases := []unpackTest{
    64  		{ // https://solidity.readthedocs.io/en/develop/abi-spec.html#use-of-dynamic-types
    65  			`[{"type":"function","name":"f", "inputs":[{"type":"uint256"},{"type":"uint32[]"},{"type":"bytes10"},{"type":"bytes"}]}]`,
    66  			// 0x123, [0x456, 0x789], "1234567890", "Hello, world!"
    67  			"8be65246" + "00000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000",
    68  			[]interface{}{
    69  				big.NewInt(0x123),
    70  				[]uint32{0x456, 0x789},
    71  				[10]byte{49, 50, 51, 52, 53, 54, 55, 56, 57, 48},
    72  				common.Hex2Bytes("48656c6c6f2c20776f726c6421"),
    73  			},
    74  		}, { // https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#examples
    75  			`[{"type":"function","name":"sam","inputs":[{"type":"bytes"},{"type":"bool"},{"type":"uint256[]"}]}]`,
    76  			//  "dave", true and [1,2,3]
    77  			"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
    78  			[]interface{}{
    79  				[]byte{0x64, 0x61, 0x76, 0x65},
    80  				true,
    81  				[]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
    82  			},
    83  		}, {
    84  			`[{"type":"function","name":"send","inputs":[{"type":"uint256"}]}]`,
    85  			"a52c101e0000000000000000000000000000000000000000000000000000000000000012",
    86  			[]interface{}{big.NewInt(0x12)},
    87  		}, {
    88  			`[{"type":"function","name":"compareAndApprove","inputs":[{"type":"address"},{"type":"uint256"},{"type":"uint256"}]}]`,
    89  			"751e107900000000000000000000000000000133700000deadbeef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
    90  			[]interface{}{
    91  				common.HexToAddress("0x00000133700000deadbeef000000000000000000"),
    92  				new(big.Int).SetBytes([]byte{0x00}),
    93  				big.NewInt(0x1),
    94  			},
    95  		},
    96  	}
    97  	for _, c := range testcases {
    98  		verify(t, c.jsondata, c.calldata, c.exp)
    99  	}
   100  
   101  }
   102  
   103  /*
   104  func TestReflect(t *testing.T) {
   105  	a := big.NewInt(0)
   106  	b := new(big.Int).SetBytes([]byte{0x00})
   107  	if !reflect.DeepEqual(a, b) {
   108  		t.Fatalf("Nope, %v != %v", a, b)
   109  	}
   110  }
   111  */
   112  
   113  func TestCalldataDecoding(t *testing.T) {
   114  
   115  	// send(uint256)                              : a52c101e
   116  	// compareAndApprove(address,uint256,uint256) : 751e1079
   117  	// issue(address[],uint256)                   : 42958b54
   118  	jsondata := `
   119  [
   120  	{"type":"function","name":"send","inputs":[{"name":"a","type":"uint256"}]},
   121  	{"type":"function","name":"compareAndApprove","inputs":[{"name":"a","type":"address"},{"name":"a","type":"uint256"},{"name":"a","type":"uint256"}]},
   122  	{"type":"function","name":"issue","inputs":[{"name":"a","type":"address[]"},{"name":"a","type":"uint256"}]},
   123  	{"type":"function","name":"sam","inputs":[{"name":"a","type":"bytes"},{"name":"a","type":"bool"},{"name":"a","type":"uint256[]"}]}
   124  ]`
   125  	//Expected failures
   126  	for _, hexdata := range []string{
   127  		"a52c101e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
   128  		"a52c101e000000000000000000000000000000000000000000000000000000000000001200",
   129  		"a52c101e00000000000000000000000000000000000000000000000000000000000000",
   130  		"a52c101e",
   131  		"a52c10",
   132  		"",
   133  		// Too short
   134  		"751e10790000000000000000000000000000000000000000000000000000000000000012",
   135  		"751e1079FFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
   136  		//Not valid multiple of 32
   137  		"deadbeef00000000000000000000000000000000000000000000000000000000000000",
   138  		//Too short 'issue'
   139  		"42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
   140  		// Too short compareAndApprove
   141  		"a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
   142  		// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
   143  		// contains a bool with illegal values
   144  		"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
   145  	} {
   146  		_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
   147  		if err == nil {
   148  			t.Errorf("Expected decoding to fail: %s", hexdata)
   149  		}
   150  	}
   151  
   152  	//Expected success
   153  	for _, hexdata := range []string{
   154  		// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
   155  		"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
   156  		"a52c101e0000000000000000000000000000000000000000000000000000000000000012",
   157  		"a52c101eFFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
   158  		"751e1079000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   159  		"42958b54" +
   160  			// start of dynamic type
   161  			"0000000000000000000000000000000000000000000000000000000000000040" +
   162  			//uint256
   163  			"0000000000000000000000000000000000000000000000000000000000000001" +
   164  			// length of  array
   165  			"0000000000000000000000000000000000000000000000000000000000000002" +
   166  			// array values
   167  			"000000000000000000000000000000000000000000000000000000000000dead" +
   168  			"000000000000000000000000000000000000000000000000000000000000beef",
   169  	} {
   170  		_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
   171  		if err != nil {
   172  			t.Errorf("Unexpected failure on input %s:\n %v (%d bytes) ", hexdata, err, len(common.Hex2Bytes(hexdata)))
   173  		}
   174  	}
   175  }
   176  
   177  func TestSelectorUnmarshalling(t *testing.T) {
   178  	var (
   179  		db        *AbiDb
   180  		err       error
   181  		abistring []byte
   182  		abistruct abi.ABI
   183  	)
   184  
   185  	db, err = NewAbiDBFromFile("../../cmd/clef/4byte.json")
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  	fmt.Printf("DB size %v\n", db.Size())
   190  	for id, selector := range db.db {
   191  
   192  		abistring, err = MethodSelectorToAbi(selector)
   193  		if err != nil {
   194  			t.Error(err)
   195  			return
   196  		}
   197  		abistruct, err = abi.JSON(strings.NewReader(string(abistring)))
   198  		if err != nil {
   199  			t.Error(err)
   200  			return
   201  		}
   202  		m, err := abistruct.MethodById(common.Hex2Bytes(id[2:]))
   203  		if err != nil {
   204  			t.Error(err)
   205  			return
   206  		}
   207  		if m.Sig() != selector {
   208  			t.Errorf("Expected equality: %v != %v", m.Sig(), selector)
   209  		}
   210  	}
   211  
   212  }
   213  
   214  func TestCustomABI(t *testing.T) {
   215  	d, err := ioutil.TempDir("", "signer-4byte-test")
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  	filename := fmt.Sprintf("%s/4byte_custom.json", d)
   220  	abidb, err := NewAbiDBFromFiles("../../cmd/clef/4byte.json", filename)
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	// Now we'll remove all existing signatures
   225  	abidb.db = make(map[string]string)
   226  	calldata := common.Hex2Bytes("a52c101edeadbeef")
   227  	_, err = abidb.LookupMethodSelector(calldata)
   228  	if err == nil {
   229  		t.Fatalf("Should not find a match on empty db")
   230  	}
   231  	if err = abidb.AddSignature("send(uint256)", calldata); err != nil {
   232  		t.Fatalf("Failed to save file: %v", err)
   233  	}
   234  	_, err = abidb.LookupMethodSelector(calldata)
   235  	if err != nil {
   236  		t.Fatalf("Should find a match for abi signature, got: %v", err)
   237  	}
   238  	//Check that it wrote to file
   239  	abidb2, err := NewAbiDBFromFile(filename)
   240  	if err != nil {
   241  		t.Fatalf("Failed to create new abidb: %v", err)
   242  	}
   243  	_, err = abidb2.LookupMethodSelector(calldata)
   244  	if err != nil {
   245  		t.Fatalf("Save failed: should find a match for abi signature after loading from disk")
   246  	}
   247  }