github.com/vechain/thor@v1.7.4/vm/contracts_test.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser 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  // The go-ethereum library 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 Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package vm
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"math/big"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  )
    30  
    31  // precompiledTest defines the input/output pairs for precompiled contract tests.
    32  type precompiledTest struct {
    33  	Input, Expected string
    34  	Gas             uint64
    35  	Name            string
    36  	NoBenchmark     bool // Benchmark primarily the worst-cases
    37  }
    38  
    39  // precompiledFailureTest defines the input/error pairs for precompiled
    40  // contract failure tests.
    41  type precompiledFailureTest struct {
    42  	Input         string
    43  	ExpectedError string
    44  	Name          string
    45  }
    46  
    47  // allPrecompiles does not map to the actual set of precompiles, as it also contains
    48  // repriced versions of precompiles at certain slots
    49  var allPrecompiles = map[common.Address]PrecompiledContract{
    50  	common.BytesToAddress([]byte{1}): &safe_ecrecover{},
    51  	common.BytesToAddress([]byte{2}): &sha256hash{},
    52  	common.BytesToAddress([]byte{3}): &ripemd160hash{},
    53  	common.BytesToAddress([]byte{4}): &dataCopy{},
    54  	common.BytesToAddress([]byte{5}): &bigModExp{},
    55  	common.BytesToAddress([]byte{6}): &bn256Add{},
    56  	common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
    57  	common.BytesToAddress([]byte{8}): &bn256Pairing{},
    58  	common.BytesToAddress([]byte{9}): &blake2F{},
    59  }
    60  
    61  // EIP-152 test vectors
    62  var blake2FMalformedInputTests = []precompiledFailureTest{
    63  	{
    64  		Input:         "",
    65  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    66  		Name:          "vector 0: empty input",
    67  	},
    68  	{
    69  		Input:         "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
    70  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    71  		Name:          "vector 1: less than 213 bytes input",
    72  	},
    73  	{
    74  		Input:         "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
    75  		ExpectedError: errBlake2FInvalidInputLength.Error(),
    76  		Name:          "vector 2: more than 213 bytes input",
    77  	},
    78  	{
    79  		Input:         "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
    80  		ExpectedError: errBlake2FInvalidFinalFlag.Error(),
    81  		Name:          "vector 3: malformed final block indicator flag",
    82  	},
    83  }
    84  
    85  func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
    86  	p := allPrecompiles[common.HexToAddress(addr)]
    87  	in := common.Hex2Bytes(test.Input)
    88  	gas := p.RequiredGas(in)
    89  	contract := NewContract(AccountRef(common.HexToAddress("1337")),
    90  		nil, new(big.Int), gas)
    91  
    92  	t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
    93  		if res, err := RunPrecompiledContract(p, in, contract); err != nil {
    94  			t.Error(err)
    95  		} else if common.Bytes2Hex(res) != test.Expected {
    96  			t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
    97  		}
    98  		if expGas := test.Gas; expGas != gas {
    99  			t.Errorf("%v: gas wrong, expected %d, got %d", test.Name, expGas, gas)
   100  		}
   101  		// Verify that the precompile did not touch the input buffer
   102  		exp := common.Hex2Bytes(test.Input)
   103  		if !bytes.Equal(in, exp) {
   104  			t.Errorf("Precompiled %v modified input data", addr)
   105  		}
   106  	})
   107  }
   108  
   109  func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
   110  	p := allPrecompiles[common.HexToAddress(addr)]
   111  	in := common.Hex2Bytes(test.Input)
   112  	gas := p.RequiredGas(in) - 1
   113  	contract := NewContract(AccountRef(common.HexToAddress("1337")),
   114  		nil, new(big.Int), gas)
   115  	t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
   116  		_, err := RunPrecompiledContract(p, in, contract)
   117  		if err.Error() != "out of gas" {
   118  			t.Errorf("Expected error [out of gas], got [%v]", err)
   119  		}
   120  		// Verify that the precompile did not touch the input buffer
   121  		exp := common.Hex2Bytes(test.Input)
   122  		if !bytes.Equal(in, exp) {
   123  			t.Errorf("Precompiled %v modified input data", addr)
   124  		}
   125  	})
   126  }
   127  
   128  func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
   129  	p := allPrecompiles[common.HexToAddress(addr)]
   130  	in := common.Hex2Bytes(test.Input)
   131  	gas := p.RequiredGas(in)
   132  	contract := NewContract(AccountRef(common.HexToAddress("1337")),
   133  		nil, new(big.Int), gas)
   134  	t.Run(test.Name, func(t *testing.T) {
   135  		_, err := RunPrecompiledContract(p, in, contract)
   136  		if err.Error() != test.ExpectedError {
   137  			t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
   138  		}
   139  		// Verify that the precompile did not touch the input buffer
   140  		exp := common.Hex2Bytes(test.Input)
   141  		if !bytes.Equal(in, exp) {
   142  			t.Errorf("Precompiled %v modified input data", addr)
   143  		}
   144  	})
   145  }
   146  
   147  func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
   148  	if test.NoBenchmark {
   149  		return
   150  	}
   151  	p := allPrecompiles[common.HexToAddress(addr)]
   152  	in := common.Hex2Bytes(test.Input)
   153  	reqGas := p.RequiredGas(in)
   154  
   155  	var (
   156  		res  []byte
   157  		err  error
   158  		data = make([]byte, len(in))
   159  	)
   160  
   161  	bench.Run(fmt.Sprintf("%s-Gas=%d", test.Name, reqGas), func(bench *testing.B) {
   162  		bench.ReportAllocs()
   163  		start := time.Now()
   164  		bench.ResetTimer()
   165  		for i := 0; i < bench.N; i++ {
   166  			copy(data, in)
   167  			contract := NewContract(AccountRef(common.HexToAddress("1337")),
   168  				nil, new(big.Int), reqGas)
   169  			res, err = RunPrecompiledContract(p, data, contract)
   170  		}
   171  		bench.StopTimer()
   172  		elapsed := uint64(time.Since(start))
   173  		if elapsed < 1 {
   174  			elapsed = 1
   175  		}
   176  		gasUsed := reqGas * uint64(bench.N)
   177  		bench.ReportMetric(float64(reqGas), "gas/op")
   178  		// Keep it as uint64, multiply 100 to get two digit float later
   179  		mgasps := (100 * 1000 * gasUsed) / elapsed
   180  		bench.ReportMetric(float64(mgasps)/100, "mgas/s")
   181  		//Check if it is correct
   182  		if err != nil {
   183  			bench.Error(err)
   184  			return
   185  		}
   186  		if common.Bytes2Hex(res) != test.Expected {
   187  			bench.Error(fmt.Sprintf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)))
   188  			return
   189  		}
   190  	})
   191  }
   192  
   193  // Benchmarks the sample inputs from the ECRECOVER precompile.
   194  func BenchmarkPrecompiledEcrecover(bench *testing.B) {
   195  	t := precompiledTest{
   196  		Input:    "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02",
   197  		Expected: "000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d",
   198  		Name:     "",
   199  	}
   200  	benchmarkPrecompiled("01", t, bench)
   201  }
   202  
   203  // Benchmarks the sample inputs from the SHA256 precompile.
   204  func BenchmarkPrecompiledSha256(bench *testing.B) {
   205  	t := precompiledTest{
   206  		Input:    "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02",
   207  		Expected: "811c7003375852fabd0d362e40e68607a12bdabae61a7d068fe5fdd1dbbf2a5d",
   208  		Name:     "128",
   209  	}
   210  	benchmarkPrecompiled("02", t, bench)
   211  }
   212  
   213  // Benchmarks the sample inputs from the RIPEMD precompile.
   214  func BenchmarkPrecompiledRipeMD(bench *testing.B) {
   215  	t := precompiledTest{
   216  		Input:    "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02",
   217  		Expected: "0000000000000000000000009215b8d9882ff46f0dfde6684d78e831467f65e6",
   218  		Name:     "128",
   219  	}
   220  	benchmarkPrecompiled("03", t, bench)
   221  }
   222  
   223  // Benchmarks the sample inputs from the identiy precompile.
   224  func BenchmarkPrecompiledIdentity(bench *testing.B) {
   225  	t := precompiledTest{
   226  		Input:    "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02",
   227  		Expected: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02",
   228  		Name:     "128",
   229  	}
   230  	benchmarkPrecompiled("04", t, bench)
   231  }
   232  
   233  // Tests the sample inputs from the ModExp EIP 198.
   234  func TestPrecompiledModExp(t *testing.T)      { testJson("modexp", "05", t) }
   235  func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) }
   236  
   237  // Tests the sample inputs from the elliptic curve addition EIP 213.
   238  func TestPrecompiledBn256Add(t *testing.T)      { testJson("bn256Add", "06", t) }
   239  func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) }
   240  
   241  // Tests OOG
   242  func TestPrecompiledModExpOOG(t *testing.T) {
   243  	modexpTests, err := loadJson("modexp")
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	for _, test := range modexpTests {
   248  		testPrecompiledOOG("05", test, t)
   249  	}
   250  }
   251  
   252  // Tests the sample inputs from the elliptic curve scalar multiplication EIP 213.
   253  func TestPrecompiledBn256ScalarMul(t *testing.T)      { testJson("bn256ScalarMul", "07", t) }
   254  func BenchmarkPrecompiledBn256ScalarMul(b *testing.B) { benchJson("bn256ScalarMul", "07", b) }
   255  
   256  // Tests the sample inputs from the elliptic curve pairing check EIP 197.
   257  func TestPrecompiledBn256Pairing(t *testing.T)      { testJson("bn256Pairing", "08", t) }
   258  func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) }
   259  
   260  func TestPrecompiledBlake2F(t *testing.T)      { testJson("blake2F", "09", t) }
   261  func BenchmarkPrecompiledBlake2F(b *testing.B) { benchJson("blake2F", "09", b) }
   262  
   263  func TestPrecompileBlake2FMalformedInput(t *testing.T) {
   264  	for _, test := range blake2FMalformedInputTests {
   265  		testPrecompiledFailure("09", test, t)
   266  	}
   267  }
   268  
   269  func TestPrecompiledEcrecover(t *testing.T) { testJson("ecRecover", "01", t) }
   270  
   271  func testJson(name, addr string, t *testing.T) {
   272  	tests, err := loadJson(name)
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  	for _, test := range tests {
   277  		testPrecompiled(addr, test, t)
   278  	}
   279  }
   280  
   281  func testJsonFail(name, addr string, t *testing.T) {
   282  	tests, err := loadJsonFail(name)
   283  	if err != nil {
   284  		t.Fatal(err)
   285  	}
   286  	for _, test := range tests {
   287  		testPrecompiledFailure(addr, test, t)
   288  	}
   289  }
   290  
   291  func benchJson(name, addr string, b *testing.B) {
   292  	tests, err := loadJson(name)
   293  	if err != nil {
   294  		b.Fatal(err)
   295  	}
   296  	for _, test := range tests {
   297  		benchmarkPrecompiled(addr, test, b)
   298  	}
   299  }
   300  
   301  func loadJson(name string) ([]precompiledTest, error) {
   302  	data, err := ioutil.ReadFile(fmt.Sprintf("testdata/precompiles/%v.json", name))
   303  	if err != nil {
   304  		return nil, err
   305  	}
   306  	var testcases []precompiledTest
   307  	err = json.Unmarshal(data, &testcases)
   308  	return testcases, err
   309  }
   310  
   311  func loadJsonFail(name string) ([]precompiledFailureTest, error) {
   312  	data, err := ioutil.ReadFile(fmt.Sprintf("testdata/precompiles/fail-%v.json", name))
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  	var testcases []precompiledFailureTest
   317  	err = json.Unmarshal(data, &testcases)
   318  	return testcases, err
   319  }