diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..32bdb3b6e5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "tests"]
+ path = tests/testdata
+ url = https://github.com/ethereum/tests
diff --git a/accounts/keystore/keystore_plain_test.go b/accounts/keystore/keystore_plain_test.go
index 8c0eb52ea1..71a45cb01f 100644
--- a/accounts/keystore/keystore_plain_test.go
+++ b/accounts/keystore/keystore_plain_test.go
@@ -142,19 +142,19 @@ func TestV3_PBKDF2_1(t *testing.T) {
func TestV3_PBKDF2_2(t *testing.T) {
t.Parallel()
- tests := loadKeyStoreTestV3("../../tests/files/KeyStoreTests/basic_tests.json", t)
+ tests := loadKeyStoreTestV3("../../tests/testdata/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["test1"], t)
}
func TestV3_PBKDF2_3(t *testing.T) {
t.Parallel()
- tests := loadKeyStoreTestV3("../../tests/files/KeyStoreTests/basic_tests.json", t)
+ tests := loadKeyStoreTestV3("../../tests/testdata/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["python_generated_test_with_odd_iv"], t)
}
func TestV3_PBKDF2_4(t *testing.T) {
t.Parallel()
- tests := loadKeyStoreTestV3("../../tests/files/KeyStoreTests/basic_tests.json", t)
+ tests := loadKeyStoreTestV3("../../tests/testdata/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["evilnonce"], t)
}
@@ -166,7 +166,7 @@ func TestV3_Scrypt_1(t *testing.T) {
func TestV3_Scrypt_2(t *testing.T) {
t.Parallel()
- tests := loadKeyStoreTestV3("../../tests/files/KeyStoreTests/basic_tests.json", t)
+ tests := loadKeyStoreTestV3("../../tests/testdata/KeyStoreTests/basic_tests.json", t)
testDecryptV3(tests["test2"], t)
}
diff --git a/build/update-license.go b/build/update-license.go
index 948eabab6f..3d69598b75 100644
--- a/build/update-license.go
+++ b/build/update-license.go
@@ -45,7 +45,7 @@ var (
// paths with any of these prefixes will be skipped
skipPrefixes = []string{
// boring stuff
- "vendor/", "tests/files/", "build/",
+ "vendor/", "tests/testdata/", "build/",
// don't relicense vendored sources
"cmd/internal/browser",
"consensus/ethash/xor.go",
diff --git a/consensus/ethash/consensus_test.go b/consensus/ethash/consensus_test.go
index 0a375b0bcb..d8f6b2b407 100644
--- a/consensus/ethash/consensus_test.go
+++ b/consensus/ethash/consensus_test.go
@@ -57,7 +57,7 @@ func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
}
func TestCalcDifficulty(t *testing.T) {
- file, err := os.Open("../../tests/files/BasicTests/difficulty.json")
+ file, err := os.Open("../../tests/testdata/BasicTests/difficulty.json")
if err != nil {
t.Fatal(err)
}
diff --git a/tests/block_test.go b/tests/block_test.go
index d341610175..3245aca7db 100644
--- a/tests/block_test.go
+++ b/tests/block_test.go
@@ -18,230 +18,64 @@ package tests
import (
"math/big"
- "path/filepath"
"testing"
+
+ "github.com/ethereum/go-ethereum/params"
)
-func TestBcValidBlockTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcValidBlockTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
+func TestBlockchain(t *testing.T) {
+ t.Parallel()
-func TestBcUncleHeaderValidityTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcUncleHeaderValiditiy.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
+ bt := new(testMatcher)
+ // General state tests are 'exported' as blockchain tests, but we can run them natively.
+ bt.skipLoad(`^GeneralStateTests/`)
+ // Skip random failures due to selfish mining test.
+ bt.skipLoad(`bcForkUncle\.json/ForkUncle`)
+ bt.skipLoad(`^bcMultiChainTest\.json/ChainAtoChainB_blockorder`)
+ bt.skipLoad(`^bcTotalDifficultyTest\.json/(lotsOfLeafs|lotsOfBranches|sideChainWithMoreTransactions)$`)
+ bt.skipLoad(`^bcMultiChainTest\.json/CallContractFromNotBestBlock`)
+ // Expected failures:
+ bt.fails(`(?i)metropolis`, "metropolis is not supported yet")
+ bt.fails(`^TestNetwork/bcTheDaoTest\.json/(DaoTransactions$|DaoTransactions_UncleExtradata$)`, "issue in test")
-func TestBcUncleTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
+ bt.config(`^TestNetwork/`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(5),
+ DAOForkBlock: big.NewInt(8),
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(10),
+ EIP155Block: big.NewInt(10),
+ EIP158Block: big.NewInt(14),
+ // MetropolisBlock: big.NewInt(16),
+ })
+ bt.config(`^RandomTests/.*EIP150`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ })
+ bt.config(`^RandomTests/.*EIP158`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ })
+ bt.config(`^RandomTests/`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(10),
+ })
+ bt.config(`^Homestead/`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ })
+ bt.config(`^EIP150/`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ })
+ bt.config(`^[^/]+\.json`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(1000000),
+ })
-func TestBcForkUncleTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcForkUncle.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcInvalidHeaderTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcInvalidRLPTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcInvalidRLPTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcRPCAPITests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcRPC_API_Test.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcForkBlockTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcForkBlockTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcForkStress(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcForkStressTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcTotalDifficulty(t *testing.T) {
- // skip because these will fail due to selfish mining fix
- t.Skip()
-
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcTotalDifficultyTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcWallet(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcWalletTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcGasPricer(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcGasPricerTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-// TODO: iterate over files once we got more than a few
-func TestBcRandom(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, big.NewInt(10), filepath.Join(blockTestDir, "RandomTests/bl201507071825GO.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcMultiChain(t *testing.T) {
- // skip due to selfish mining
- t.Skip()
-
- err := RunBlockTest(big.NewInt(1000000), nil, big.NewInt(10), filepath.Join(blockTestDir, "bcMultiChainTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBcState(t *testing.T) {
- err := RunBlockTest(big.NewInt(1000000), nil, big.NewInt(10), filepath.Join(blockTestDir, "bcStateTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-// Homestead tests
-func TestHomesteadBcValidBlockTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcValidBlockTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcUncleHeaderValidityTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcUncleHeaderValiditiy.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcUncleTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcUncleTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcInvalidHeaderTests(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcInvalidHeaderTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcRPCAPITests(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcRPC_API_Test.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcForkStress(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcForkStressTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcTotalDifficulty(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcTotalDifficultyTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcWallet(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcWalletTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcGasPricer(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcGasPricerTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcMultiChain(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcMultiChainTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcState(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcStateTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-// DAO hard-fork tests
-func TestDAOBcTheDao(t *testing.T) {
- err := RunBlockTest(big.NewInt(5), big.NewInt(8), nil, filepath.Join(blockTestDir, "TestNetwork", "bcTheDaoTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestEIP150Bc(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), big.NewInt(8), big.NewInt(10), filepath.Join(blockTestDir, "TestNetwork", "bcEIP150Test.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadBcExploit(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcExploitTest.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-func TestHomesteadBcShanghaiLove(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcShanghaiLove.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-func TestHomesteadBcSuicideIssue(t *testing.T) {
- err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcSuicideIssue.json"), BlockSkipTests)
- if err != nil {
- t.Fatal(err)
- }
+ bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
+ cfg := bt.findConfig(name)
+ if err := bt.checkFailure(t, name, test.Run(cfg)); err != nil {
+ t.Error(err)
+ }
+ })
}
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 24d4672b64..a74f7d68dd 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -14,19 +14,19 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
+// Package tests implements execution of Ethereum JSON tests.
package tests
import (
"bytes"
"encoding/hex"
+ "encoding/json"
"fmt"
- "io"
"math/big"
- "runtime"
- "strconv"
- "strings"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
@@ -34,212 +34,115 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
-// Block Test JSON Format
+// A BlockTest checks handling of entire blocks.
type BlockTest struct {
- Genesis *types.Block
+ json btJSON
+}
- Json *btJSON
- preAccounts map[string]btAccount
- postAccounts map[string]btAccount
- lastblockhash string
+func (t *BlockTest) UnmarshalJSON(in []byte) error {
+ return json.Unmarshal(in, &t.json)
}
type btJSON struct {
- Blocks []btBlock
- GenesisBlockHeader btHeader
- Pre map[string]btAccount
- PostState map[string]btAccount
- Lastblockhash string
+ Blocks []btBlock `json:"blocks"`
+ Genesis btHeader `json:"genesisBlockHeader"`
+ Pre core.GenesisAlloc `json:"pre"`
+ Post core.GenesisAlloc `json:"postState"`
+ BestBlock common.UnprefixedHash `json:"lastblockhash"`
}
type btBlock struct {
BlockHeader *btHeader
Rlp string
- Transactions []btTransaction
UncleHeaders []*btHeader
}
-type btAccount struct {
- Balance string
- Code string
- Nonce string
- Storage map[string]string
- PrivateKey string
-}
+//go:generate gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go
type btHeader struct {
- Bloom string
- Coinbase string
- MixHash string
- Nonce string
- Number string
- Hash string
- ParentHash string
- ReceiptTrie string
- SeedHash string
- StateRoot string
- TransactionsTrie string
- UncleHash string
-
- ExtraData string
- Difficulty string
- GasLimit string
- GasUsed string
- Timestamp string
+ Bloom types.Bloom
+ Coinbase common.Address
+ MixHash common.Hash
+ Nonce types.BlockNonce
+ Number *big.Int
+ Hash common.Hash
+ ParentHash common.Hash
+ ReceiptTrie common.Hash
+ StateRoot common.Hash
+ TransactionsTrie common.Hash
+ UncleHash common.Hash
+ ExtraData []byte
+ Difficulty *big.Int
+ GasLimit *big.Int
+ GasUsed *big.Int
+ Timestamp *big.Int
}
-type btTransaction struct {
- Data string
- GasLimit string
- GasPrice string
- Nonce string
- R string
- S string
- To string
- V string
- Value string
+type btHeaderMarshaling struct {
+ ExtraData hexutil.Bytes
+ Number *math.HexOrDecimal256
+ Difficulty *math.HexOrDecimal256
+ GasLimit *math.HexOrDecimal256
+ GasUsed *math.HexOrDecimal256
+ Timestamp *math.HexOrDecimal256
}
-func RunBlockTestWithReader(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, r io.Reader, skipTests []string) error {
- btjs := make(map[string]*btJSON)
- if err := readJson(r, &btjs); err != nil {
- return err
- }
-
- bt, err := convertBlockTests(btjs)
- if err != nil {
- return err
- }
-
- if err := runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork, bt, skipTests); err != nil {
- return err
- }
- return nil
-}
-
-func RunBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, file string, skipTests []string) error {
- btjs := make(map[string]*btJSON)
- if err := readJsonFile(file, &btjs); err != nil {
- return err
- }
-
- bt, err := convertBlockTests(btjs)
- if err != nil {
- return err
- }
- if err := runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork, bt, skipTests); err != nil {
- return err
- }
- return nil
-}
-
-func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[string]*BlockTest, skipTests []string) error {
- skipTest := make(map[string]bool, len(skipTests))
- for _, name := range skipTests {
- skipTest[name] = true
- }
-
- for name, test := range bt {
- if skipTest[name] /*|| name != "CallingCanonicalContractFromFork_CALLCODE"*/ {
- log.Info(fmt.Sprint("Skipping block test", name))
- continue
- }
- // test the block
- if err := runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork, test); err != nil {
- return fmt.Errorf("%s: %v", name, err)
- }
- log.Info(fmt.Sprint("Block test passed: ", name))
-
- }
- return nil
-}
-
-func runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, test *BlockTest) error {
+func (t *BlockTest) Run(config *params.ChainConfig) error {
// import pre accounts & construct test genesis block & state root
db, _ := ethdb.NewMemDatabase()
- if _, err := test.InsertPreState(db); err != nil {
- return fmt.Errorf("InsertPreState: %v", err)
+ gblock, err := t.genesis(config).Commit(db)
+ if err != nil {
+ return err
+ }
+ if gblock.Hash() != t.json.Genesis.Hash {
+ return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x\n", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6])
+ }
+ if gblock.Root() != t.json.Genesis.StateRoot {
+ return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
}
- core.WriteTd(db, test.Genesis.Hash(), 0, test.Genesis.Difficulty())
- core.WriteBlock(db, test.Genesis)
- core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64())
- core.WriteHeadBlockHash(db, test.Genesis.Hash())
- evmux := new(event.TypeMux)
- config := ¶ms.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, EIP150Block: gasPriceFork}
- chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux, vm.Config{})
+ chain, err := core.NewBlockChain(db, config, ethash.NewShared(), new(event.TypeMux), vm.Config{})
if err != nil {
return err
}
defer chain.Stop()
- //vm.Debug = true
- validBlocks, err := test.TryBlocksInsert(chain)
+ validBlocks, err := t.insertBlocks(chain)
if err != nil {
return err
}
-
- lastblockhash := common.HexToHash(test.lastblockhash)
cmlast := chain.LastBlockHash()
- if lastblockhash != cmlast {
- return fmt.Errorf("lastblockhash validation mismatch: want: %x, have: %x", lastblockhash, cmlast)
+ if common.Hash(t.json.BestBlock) != cmlast {
+ return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
}
-
newDB, err := chain.State()
if err != nil {
return err
}
- if err = test.ValidatePostState(newDB); err != nil {
+ if err = t.validatePostState(newDB); err != nil {
return fmt.Errorf("post state validation failed: %v", err)
}
-
- return test.ValidateImportedHeaders(chain, validBlocks)
+ return t.validateImportedHeaders(chain, validBlocks)
}
-// InsertPreState populates the given database with the genesis
-// accounts defined by the test.
-func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
- statedb, err := state.New(common.Hash{}, state.NewDatabase(db))
- if err != nil {
- return nil, err
+func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis {
+ return &core.Genesis{
+ Config: config,
+ Nonce: t.json.Genesis.Nonce.Uint64(),
+ Timestamp: t.json.Genesis.Timestamp.Uint64(),
+ ParentHash: t.json.Genesis.ParentHash,
+ ExtraData: t.json.Genesis.ExtraData,
+ GasLimit: t.json.Genesis.GasLimit.Uint64(),
+ GasUsed: t.json.Genesis.GasUsed.Uint64(),
+ Difficulty: t.json.Genesis.Difficulty,
+ Mixhash: t.json.Genesis.MixHash,
+ Coinbase: t.json.Genesis.Coinbase,
+ Alloc: t.json.Pre,
}
- for addrString, acct := range t.preAccounts {
- code, err := hex.DecodeString(strings.TrimPrefix(acct.Code, "0x"))
- if err != nil {
- return nil, err
- }
- balance, ok := new(big.Int).SetString(acct.Balance, 0)
- if !ok {
- return nil, err
- }
- nonce, err := strconv.ParseUint(prepInt(16, acct.Nonce), 16, 64)
- if err != nil {
- return nil, err
- }
-
- addr := common.HexToAddress(addrString)
- statedb.CreateAccount(addr)
- statedb.SetCode(addr, code)
- statedb.SetBalance(addr, balance)
- statedb.SetNonce(addr, nonce)
- for k, v := range acct.Storage {
- statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.HexToHash(v))
- }
- }
-
- root, err := statedb.CommitTo(db, false)
- if err != nil {
- return nil, fmt.Errorf("error writing state: %v", err)
- }
- if t.Genesis.Root() != root {
- return nil, fmt.Errorf("computed state root does not match genesis block: genesis=%x computed=%x", t.Genesis.Root().Bytes()[:4], root.Bytes()[:4])
- }
- return statedb, nil
}
/* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II
@@ -254,11 +157,11 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
expected we are expected to ignore it and continue processing and then validate the
post state.
*/
-func (t *BlockTest) TryBlocksInsert(blockchain *core.BlockChain) ([]btBlock, error) {
+func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) {
validBlocks := make([]btBlock, 0)
// insert the test blocks, which will execute all transactions
- for _, b := range t.Json.Blocks {
- cb, err := mustConvertBlock(b)
+ for _, b := range t.json.Blocks {
+ cb, err := b.decode()
if err != nil {
if b.BlockHeader == nil {
continue // OK - block is supposed to be invalid, continue with next block
@@ -290,288 +193,99 @@ func (t *BlockTest) TryBlocksInsert(blockchain *core.BlockChain) ([]btBlock, err
}
func validateHeader(h *btHeader, h2 *types.Header) error {
- expectedBloom := mustConvertBytes(h.Bloom)
- if !bytes.Equal(expectedBloom, h2.Bloom.Bytes()) {
- return fmt.Errorf("Bloom: want: %x have: %x", expectedBloom, h2.Bloom.Bytes())
+ if h.Bloom != h2.Bloom {
+ return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom)
}
-
- expectedCoinbase := mustConvertBytes(h.Coinbase)
- if !bytes.Equal(expectedCoinbase, h2.Coinbase.Bytes()) {
- return fmt.Errorf("Coinbase: want: %x have: %x", expectedCoinbase, h2.Coinbase.Bytes())
+ if h.Coinbase != h2.Coinbase {
+ return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
}
-
- expectedMixHashBytes := mustConvertBytes(h.MixHash)
- if !bytes.Equal(expectedMixHashBytes, h2.MixDigest.Bytes()) {
- return fmt.Errorf("MixHash: want: %x have: %x", expectedMixHashBytes, h2.MixDigest.Bytes())
+ if h.MixHash != h2.MixDigest {
+ return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
}
-
- expectedNonce := mustConvertBytes(h.Nonce)
- if !bytes.Equal(expectedNonce, h2.Nonce[:]) {
- return fmt.Errorf("Nonce: want: %x have: %x", expectedNonce, h2.Nonce)
+ if h.Nonce != h2.Nonce {
+ return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce)
}
-
- expectedNumber := mustConvertBigInt(h.Number, 16)
- if expectedNumber.Cmp(h2.Number) != 0 {
- return fmt.Errorf("Number: want: %v have: %v", expectedNumber, h2.Number)
+ if h.Number.Cmp(h2.Number) != 0 {
+ return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number)
}
-
- expectedParentHash := mustConvertBytes(h.ParentHash)
- if !bytes.Equal(expectedParentHash, h2.ParentHash.Bytes()) {
- return fmt.Errorf("Parent hash: want: %x have: %x", expectedParentHash, h2.ParentHash.Bytes())
+ if h.ParentHash != h2.ParentHash {
+ return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
}
-
- expectedReceiptHash := mustConvertBytes(h.ReceiptTrie)
- if !bytes.Equal(expectedReceiptHash, h2.ReceiptHash.Bytes()) {
- return fmt.Errorf("Receipt hash: want: %x have: %x", expectedReceiptHash, h2.ReceiptHash.Bytes())
+ if h.ReceiptTrie != h2.ReceiptHash {
+ return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
}
-
- expectedTxHash := mustConvertBytes(h.TransactionsTrie)
- if !bytes.Equal(expectedTxHash, h2.TxHash.Bytes()) {
- return fmt.Errorf("Tx hash: want: %x have: %x", expectedTxHash, h2.TxHash.Bytes())
+ if h.TransactionsTrie != h2.TxHash {
+ return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
}
-
- expectedStateHash := mustConvertBytes(h.StateRoot)
- if !bytes.Equal(expectedStateHash, h2.Root.Bytes()) {
- return fmt.Errorf("State hash: want: %x have: %x", expectedStateHash, h2.Root.Bytes())
+ if h.StateRoot != h2.Root {
+ return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root)
}
-
- expectedUncleHash := mustConvertBytes(h.UncleHash)
- if !bytes.Equal(expectedUncleHash, h2.UncleHash.Bytes()) {
- return fmt.Errorf("Uncle hash: want: %x have: %x", expectedUncleHash, h2.UncleHash.Bytes())
+ if h.UncleHash != h2.UncleHash {
+ return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
}
-
- expectedExtraData := mustConvertBytes(h.ExtraData)
- if !bytes.Equal(expectedExtraData, h2.Extra) {
- return fmt.Errorf("Extra data: want: %x have: %x", expectedExtraData, h2.Extra)
+ if !bytes.Equal(h.ExtraData, h2.Extra) {
+ return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra)
}
-
- expectedDifficulty := mustConvertBigInt(h.Difficulty, 16)
- if expectedDifficulty.Cmp(h2.Difficulty) != 0 {
- return fmt.Errorf("Difficulty: want: %v have: %v", expectedDifficulty, h2.Difficulty)
+ if h.Difficulty.Cmp(h2.Difficulty) != 0 {
+ return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
}
-
- expectedGasLimit := mustConvertBigInt(h.GasLimit, 16)
- if expectedGasLimit.Cmp(h2.GasLimit) != 0 {
- return fmt.Errorf("GasLimit: want: %v have: %v", expectedGasLimit, h2.GasLimit)
+ if h.GasLimit.Cmp(h2.GasLimit) != 0 {
+ return fmt.Errorf("GasLimit: want: %v have: %v", h.GasLimit, h2.GasLimit)
}
- expectedGasUsed := mustConvertBigInt(h.GasUsed, 16)
- if expectedGasUsed.Cmp(h2.GasUsed) != 0 {
- return fmt.Errorf("GasUsed: want: %v have: %v", expectedGasUsed, h2.GasUsed)
+ if h.GasUsed.Cmp(h2.GasUsed) != 0 {
+ return fmt.Errorf("GasUsed: want: %v have: %v", h.GasUsed, h2.GasUsed)
}
-
- expectedTimestamp := mustConvertBigInt(h.Timestamp, 16)
- if expectedTimestamp.Cmp(h2.Time) != 0 {
- return fmt.Errorf("Timestamp: want: %v have: %v", expectedTimestamp, h2.Time)
+ if h.Timestamp.Cmp(h2.Time) != 0 {
+ return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time)
}
-
return nil
}
-func (t *BlockTest) ValidatePostState(statedb *state.StateDB) error {
+func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
// validate post state accounts in test file against what we have in state db
- for addrString, acct := range t.postAccounts {
- // XXX: is is worth it checking for errors here?
- addr, err := hex.DecodeString(addrString)
- if err != nil {
- return err
- }
- code, err := hex.DecodeString(strings.TrimPrefix(acct.Code, "0x"))
- if err != nil {
- return err
- }
- balance, ok := new(big.Int).SetString(acct.Balance, 0)
- if !ok {
- return err
- }
- nonce, err := strconv.ParseUint(prepInt(16, acct.Nonce), 16, 64)
- if err != nil {
- return err
- }
-
+ for addr, acct := range t.json.Post {
// address is indirectly verified by the other fields, as it's the db key
- code2 := statedb.GetCode(common.BytesToAddress(addr))
- balance2 := statedb.GetBalance(common.BytesToAddress(addr))
- nonce2 := statedb.GetNonce(common.BytesToAddress(addr))
- if !bytes.Equal(code2, code) {
- return fmt.Errorf("account code mismatch for addr: %s want: %s have: %s", addrString, hex.EncodeToString(code), hex.EncodeToString(code2))
+ code2 := statedb.GetCode(addr)
+ balance2 := statedb.GetBalance(addr)
+ nonce2 := statedb.GetNonce(addr)
+ if !bytes.Equal(code2, acct.Code) {
+ return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
}
- if balance2.Cmp(balance) != 0 {
- return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addrString, balance, balance2)
+ if balance2.Cmp(acct.Balance) != 0 {
+ return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
}
- if nonce2 != nonce {
- return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addrString, nonce, nonce2)
+ if nonce2 != acct.Nonce {
+ return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
}
}
return nil
}
-func (test *BlockTest) ValidateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
+func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
// to get constant lookup when verifying block headers by hash (some tests have many blocks)
- bmap := make(map[string]btBlock, len(test.Json.Blocks))
+ bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
for _, b := range validBlocks {
bmap[b.BlockHeader.Hash] = b
}
-
// iterate over blocks backwards from HEAD and validate imported
// headers vs test file. some tests have reorgs, and we import
// block-by-block, so we can only validate imported headers after
- // all blocks have been processed by ChainManager, as they may not
+ // all blocks have been processed by BlockChain, as they may not
// be part of the longest chain until last block is imported.
for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) {
- bHash := common.Bytes2Hex(b.Hash().Bytes()) // hex without 0x prefix
- if err := validateHeader(bmap[bHash].BlockHeader, b.Header()); err != nil {
+ if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil {
return fmt.Errorf("Imported block header validation failed: %v", err)
}
}
return nil
}
-func convertBlockTests(in map[string]*btJSON) (map[string]*BlockTest, error) {
- out := make(map[string]*BlockTest)
- for name, test := range in {
- var err error
- if out[name], err = convertBlockTest(test); err != nil {
- return out, fmt.Errorf("bad test %q: %v", name, err)
- }
- }
- return out, nil
-}
-
-func convertBlockTest(in *btJSON) (out *BlockTest, err error) {
- // the conversion handles errors by catching panics.
- // you might consider this ugly, but the alternative (passing errors)
- // would be much harder to read.
- defer func() {
- if recovered := recover(); recovered != nil {
- buf := make([]byte, 64<<10)
- buf = buf[:runtime.Stack(buf, false)]
- err = fmt.Errorf("%v\n%s", recovered, buf)
- }
- }()
- out = &BlockTest{preAccounts: in.Pre, postAccounts: in.PostState, Json: in, lastblockhash: in.Lastblockhash}
- out.Genesis = mustConvertGenesis(in.GenesisBlockHeader)
- return out, err
-}
-
-func mustConvertGenesis(testGenesis btHeader) *types.Block {
- hdr := mustConvertHeader(testGenesis)
- hdr.Number = big.NewInt(0)
-
- return types.NewBlockWithHeader(hdr)
-}
-
-func mustConvertHeader(in btHeader) *types.Header {
- // hex decode these fields
- header := &types.Header{
- //SeedHash: mustConvertBytes(in.SeedHash),
- MixDigest: mustConvertHash(in.MixHash),
- Bloom: mustConvertBloom(in.Bloom),
- ReceiptHash: mustConvertHash(in.ReceiptTrie),
- TxHash: mustConvertHash(in.TransactionsTrie),
- Root: mustConvertHash(in.StateRoot),
- Coinbase: mustConvertAddress(in.Coinbase),
- UncleHash: mustConvertHash(in.UncleHash),
- ParentHash: mustConvertHash(in.ParentHash),
- Extra: mustConvertBytes(in.ExtraData),
- GasUsed: mustConvertBigInt(in.GasUsed, 16),
- GasLimit: mustConvertBigInt(in.GasLimit, 16),
- Difficulty: mustConvertBigInt(in.Difficulty, 16),
- Time: mustConvertBigInt(in.Timestamp, 16),
- Nonce: types.EncodeNonce(mustConvertUint(in.Nonce, 16)),
- }
- return header
-}
-
-func mustConvertBlock(testBlock btBlock) (*types.Block, error) {
- var b types.Block
- r := bytes.NewReader(mustConvertBytes(testBlock.Rlp))
- err := rlp.Decode(r, &b)
- return &b, err
-}
-
-func mustConvertBytes(in string) []byte {
- if in == "0x" {
- return []byte{}
- }
- h := unfuckFuckedHex(strings.TrimPrefix(in, "0x"))
- out, err := hex.DecodeString(h)
+func (bb *btBlock) decode() (*types.Block, error) {
+ data, err := hexutil.Decode(bb.Rlp)
if err != nil {
- panic(fmt.Errorf("invalid hex: %q", h))
- }
- return out
-}
-
-func mustConvertHash(in string) common.Hash {
- out, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
- if err != nil {
- panic(fmt.Errorf("invalid hex: %q", in))
- }
- return common.BytesToHash(out)
-}
-
-func mustConvertAddress(in string) common.Address {
- out, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
- if err != nil {
- panic(fmt.Errorf("invalid hex: %q", in))
- }
- return common.BytesToAddress(out)
-}
-
-func mustConvertBloom(in string) types.Bloom {
- out, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
- if err != nil {
- panic(fmt.Errorf("invalid hex: %q", in))
- }
- return types.BytesToBloom(out)
-}
-
-func mustConvertBigInt(in string, base int) *big.Int {
- in = prepInt(base, in)
- out, ok := new(big.Int).SetString(in, base)
- if !ok {
- panic(fmt.Errorf("invalid integer: %q", in))
- }
- return out
-}
-
-func mustConvertUint(in string, base int) uint64 {
- in = prepInt(base, in)
- out, err := strconv.ParseUint(in, base, 64)
- if err != nil {
- panic(fmt.Errorf("invalid integer: %q", in))
- }
- return out
-}
-
-func LoadBlockTests(file string) (map[string]*BlockTest, error) {
- btjs := make(map[string]*btJSON)
- if err := readJsonFile(file, &btjs); err != nil {
return nil, err
}
-
- return convertBlockTests(btjs)
-}
-
-// Nothing to see here, please move along...
-func prepInt(base int, s string) string {
- if base == 16 {
- s = strings.TrimPrefix(s, "0x")
- if len(s) == 0 {
- s = "00"
- }
- s = nibbleFix(s)
- }
- return s
-}
-
-// don't ask
-func unfuckFuckedHex(almostHex string) string {
- return nibbleFix(strings.Replace(almostHex, "v", "", -1))
-}
-
-func nibbleFix(s string) string {
- if len(s)%2 != 0 {
- s = "0" + s
- }
- return s
+ var b types.Block
+ err = rlp.DecodeBytes(data, &b)
+ return &b, err
}
diff --git a/tests/gen_btheader.go b/tests/gen_btheader.go
new file mode 100644
index 0000000000..5d65e0dbce
--- /dev/null
+++ b/tests/gen_btheader.go
@@ -0,0 +1,128 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package tests
+
+import (
+ "encoding/json"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+var _ = (*btHeaderMarshaling)(nil)
+
+func (b btHeader) MarshalJSON() ([]byte, error) {
+ type btHeader struct {
+ Bloom types.Bloom
+ Coinbase common.Address
+ MixHash common.Hash
+ Nonce types.BlockNonce
+ Number *math.HexOrDecimal256
+ Hash common.Hash
+ ParentHash common.Hash
+ ReceiptTrie common.Hash
+ StateRoot common.Hash
+ TransactionsTrie common.Hash
+ UncleHash common.Hash
+ ExtraData hexutil.Bytes
+ Difficulty *math.HexOrDecimal256
+ GasLimit *math.HexOrDecimal256
+ GasUsed *math.HexOrDecimal256
+ Timestamp *math.HexOrDecimal256
+ }
+ var enc btHeader
+ enc.Bloom = b.Bloom
+ enc.Coinbase = b.Coinbase
+ enc.MixHash = b.MixHash
+ enc.Nonce = b.Nonce
+ enc.Number = (*math.HexOrDecimal256)(b.Number)
+ enc.Hash = b.Hash
+ enc.ParentHash = b.ParentHash
+ enc.ReceiptTrie = b.ReceiptTrie
+ enc.StateRoot = b.StateRoot
+ enc.TransactionsTrie = b.TransactionsTrie
+ enc.UncleHash = b.UncleHash
+ enc.ExtraData = b.ExtraData
+ enc.Difficulty = (*math.HexOrDecimal256)(b.Difficulty)
+ enc.GasLimit = (*math.HexOrDecimal256)(b.GasLimit)
+ enc.GasUsed = (*math.HexOrDecimal256)(b.GasUsed)
+ enc.Timestamp = (*math.HexOrDecimal256)(b.Timestamp)
+ return json.Marshal(&enc)
+}
+
+func (b *btHeader) UnmarshalJSON(input []byte) error {
+ type btHeader struct {
+ Bloom *types.Bloom
+ Coinbase *common.Address
+ MixHash *common.Hash
+ Nonce *types.BlockNonce
+ Number *math.HexOrDecimal256
+ Hash *common.Hash
+ ParentHash *common.Hash
+ ReceiptTrie *common.Hash
+ StateRoot *common.Hash
+ TransactionsTrie *common.Hash
+ UncleHash *common.Hash
+ ExtraData hexutil.Bytes
+ Difficulty *math.HexOrDecimal256
+ GasLimit *math.HexOrDecimal256
+ GasUsed *math.HexOrDecimal256
+ Timestamp *math.HexOrDecimal256
+ }
+ var dec btHeader
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Bloom != nil {
+ b.Bloom = *dec.Bloom
+ }
+ if dec.Coinbase != nil {
+ b.Coinbase = *dec.Coinbase
+ }
+ if dec.MixHash != nil {
+ b.MixHash = *dec.MixHash
+ }
+ if dec.Nonce != nil {
+ b.Nonce = *dec.Nonce
+ }
+ if dec.Number != nil {
+ b.Number = (*big.Int)(dec.Number)
+ }
+ if dec.Hash != nil {
+ b.Hash = *dec.Hash
+ }
+ if dec.ParentHash != nil {
+ b.ParentHash = *dec.ParentHash
+ }
+ if dec.ReceiptTrie != nil {
+ b.ReceiptTrie = *dec.ReceiptTrie
+ }
+ if dec.StateRoot != nil {
+ b.StateRoot = *dec.StateRoot
+ }
+ if dec.TransactionsTrie != nil {
+ b.TransactionsTrie = *dec.TransactionsTrie
+ }
+ if dec.UncleHash != nil {
+ b.UncleHash = *dec.UncleHash
+ }
+ if dec.ExtraData != nil {
+ b.ExtraData = dec.ExtraData
+ }
+ if dec.Difficulty != nil {
+ b.Difficulty = (*big.Int)(dec.Difficulty)
+ }
+ if dec.GasLimit != nil {
+ b.GasLimit = (*big.Int)(dec.GasLimit)
+ }
+ if dec.GasUsed != nil {
+ b.GasUsed = (*big.Int)(dec.GasUsed)
+ }
+ if dec.Timestamp != nil {
+ b.Timestamp = (*big.Int)(dec.Timestamp)
+ }
+ return nil
+}
diff --git a/tests/gen_stenv.go b/tests/gen_stenv.go
new file mode 100644
index 0000000000..c780524bc3
--- /dev/null
+++ b/tests/gen_stenv.go
@@ -0,0 +1,66 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package tests
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+)
+
+var _ = (*stEnvMarshaling)(nil)
+
+func (s stEnv) MarshalJSON() ([]byte, error) {
+ type stEnv struct {
+ Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
+ Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
+ GasLimit *math.HexOrDecimal256 `json:"currentGasLimit" gencodec:"required"`
+ Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
+ Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
+ }
+ var enc stEnv
+ enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
+ enc.Difficulty = (*math.HexOrDecimal256)(s.Difficulty)
+ enc.GasLimit = (*math.HexOrDecimal256)(s.GasLimit)
+ enc.Number = math.HexOrDecimal64(s.Number)
+ enc.Timestamp = math.HexOrDecimal64(s.Timestamp)
+ return json.Marshal(&enc)
+}
+
+func (s *stEnv) UnmarshalJSON(input []byte) error {
+ type stEnv struct {
+ Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
+ Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
+ GasLimit *math.HexOrDecimal256 `json:"currentGasLimit" gencodec:"required"`
+ Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
+ Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
+ }
+ var dec stEnv
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Coinbase == nil {
+ return errors.New("missing required field 'currentCoinbase' for stEnv")
+ }
+ s.Coinbase = common.Address(*dec.Coinbase)
+ if dec.Difficulty == nil {
+ return errors.New("missing required field 'currentDifficulty' for stEnv")
+ }
+ s.Difficulty = (*big.Int)(dec.Difficulty)
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'currentGasLimit' for stEnv")
+ }
+ s.GasLimit = (*big.Int)(dec.GasLimit)
+ if dec.Number == nil {
+ return errors.New("missing required field 'currentNumber' for stEnv")
+ }
+ s.Number = uint64(*dec.Number)
+ if dec.Timestamp == nil {
+ return errors.New("missing required field 'currentTimestamp' for stEnv")
+ }
+ s.Timestamp = uint64(*dec.Timestamp)
+ return nil
+}
diff --git a/tests/gen_stlog.go b/tests/gen_stlog.go
new file mode 100644
index 0000000000..4f7ebc9660
--- /dev/null
+++ b/tests/gen_stlog.go
@@ -0,0 +1,61 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package tests
+
+import (
+ "encoding/json"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+var _ = (*stLogMarshaling)(nil)
+
+func (s stLog) MarshalJSON() ([]byte, error) {
+ type stLog struct {
+ Address common.UnprefixedAddress `json:"address"`
+ Data hexutil.Bytes `json:"data"`
+ Topics []common.UnprefixedHash `json:"topics"`
+ Bloom string `json:"bloom"`
+ }
+ var enc stLog
+ enc.Address = common.UnprefixedAddress(s.Address)
+ enc.Data = s.Data
+ if s.Topics != nil {
+ enc.Topics = make([]common.UnprefixedHash, len(s.Topics))
+ for k, v := range s.Topics {
+ enc.Topics[k] = common.UnprefixedHash(v)
+ }
+ }
+ enc.Bloom = s.Bloom
+ return json.Marshal(&enc)
+}
+
+func (s *stLog) UnmarshalJSON(input []byte) error {
+ type stLog struct {
+ Address *common.UnprefixedAddress `json:"address"`
+ Data hexutil.Bytes `json:"data"`
+ Topics []common.UnprefixedHash `json:"topics"`
+ Bloom *string `json:"bloom"`
+ }
+ var dec stLog
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Address != nil {
+ s.Address = common.Address(*dec.Address)
+ }
+ if dec.Data != nil {
+ s.Data = dec.Data
+ }
+ if dec.Topics != nil {
+ s.Topics = make([]common.Hash, len(dec.Topics))
+ for k, v := range dec.Topics {
+ s.Topics[k] = common.Hash(v)
+ }
+ }
+ if dec.Bloom != nil {
+ s.Bloom = *dec.Bloom
+ }
+ return nil
+}
diff --git a/tests/gen_sttransaction.go b/tests/gen_sttransaction.go
new file mode 100644
index 0000000000..5a489d00b8
--- /dev/null
+++ b/tests/gen_sttransaction.go
@@ -0,0 +1,80 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package tests
+
+import (
+ "encoding/json"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
+)
+
+var _ = (*stTransactionMarshaling)(nil)
+
+func (s stTransaction) MarshalJSON() ([]byte, error) {
+ type stTransaction struct {
+ GasPrice *math.HexOrDecimal256 `json:"gasPrice"`
+ Nonce math.HexOrDecimal64 `json:"nonce"`
+ To string `json:"to"`
+ Data []string `json:"data"`
+ GasLimit []math.HexOrDecimal64 `json:"gasLimit"`
+ Value []string `json:"value"`
+ PrivateKey hexutil.Bytes `json:"secretKey"`
+ }
+ var enc stTransaction
+ enc.GasPrice = (*math.HexOrDecimal256)(s.GasPrice)
+ enc.Nonce = math.HexOrDecimal64(s.Nonce)
+ enc.To = s.To
+ enc.Data = s.Data
+ if s.GasLimit != nil {
+ enc.GasLimit = make([]math.HexOrDecimal64, len(s.GasLimit))
+ for k, v := range s.GasLimit {
+ enc.GasLimit[k] = math.HexOrDecimal64(v)
+ }
+ }
+ enc.Value = s.Value
+ enc.PrivateKey = s.PrivateKey
+ return json.Marshal(&enc)
+}
+
+func (s *stTransaction) UnmarshalJSON(input []byte) error {
+ type stTransaction struct {
+ GasPrice *math.HexOrDecimal256 `json:"gasPrice"`
+ Nonce *math.HexOrDecimal64 `json:"nonce"`
+ To *string `json:"to"`
+ Data []string `json:"data"`
+ GasLimit []math.HexOrDecimal64 `json:"gasLimit"`
+ Value []string `json:"value"`
+ PrivateKey hexutil.Bytes `json:"secretKey"`
+ }
+ var dec stTransaction
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.GasPrice != nil {
+ s.GasPrice = (*big.Int)(dec.GasPrice)
+ }
+ if dec.Nonce != nil {
+ s.Nonce = uint64(*dec.Nonce)
+ }
+ if dec.To != nil {
+ s.To = *dec.To
+ }
+ if dec.Data != nil {
+ s.Data = dec.Data
+ }
+ if dec.GasLimit != nil {
+ s.GasLimit = make([]uint64, len(dec.GasLimit))
+ for k, v := range dec.GasLimit {
+ s.GasLimit[k] = uint64(v)
+ }
+ }
+ if dec.Value != nil {
+ s.Value = dec.Value
+ }
+ if dec.PrivateKey != nil {
+ s.PrivateKey = dec.PrivateKey
+ }
+ return nil
+}
diff --git a/tests/gen_tttransaction.go b/tests/gen_tttransaction.go
new file mode 100644
index 0000000000..b6759be912
--- /dev/null
+++ b/tests/gen_tttransaction.go
@@ -0,0 +1,95 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package tests
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
+)
+
+var _ = (*ttTransactionMarshaling)(nil)
+
+func (t ttTransaction) MarshalJSON() ([]byte, error) {
+ type ttTransaction struct {
+ Data hexutil.Bytes `gencodec:"required"`
+ GasLimit *math.HexOrDecimal256 `gencodec:"required"`
+ GasPrice *math.HexOrDecimal256 `gencodec:"required"`
+ Nonce math.HexOrDecimal64 `gencodec:"required"`
+ Value *math.HexOrDecimal256 `gencodec:"required"`
+ R *math.HexOrDecimal256 `gencodec:"required"`
+ S *math.HexOrDecimal256 `gencodec:"required"`
+ V *math.HexOrDecimal256 `gencodec:"required"`
+ To common.Address `gencodec:"required"`
+ }
+ var enc ttTransaction
+ enc.Data = t.Data
+ enc.GasLimit = (*math.HexOrDecimal256)(t.GasLimit)
+ enc.GasPrice = (*math.HexOrDecimal256)(t.GasPrice)
+ enc.Nonce = math.HexOrDecimal64(t.Nonce)
+ enc.Value = (*math.HexOrDecimal256)(t.Value)
+ enc.R = (*math.HexOrDecimal256)(t.R)
+ enc.S = (*math.HexOrDecimal256)(t.S)
+ enc.V = (*math.HexOrDecimal256)(t.V)
+ enc.To = t.To
+ return json.Marshal(&enc)
+}
+
+func (t *ttTransaction) UnmarshalJSON(input []byte) error {
+ type ttTransaction struct {
+ Data hexutil.Bytes `gencodec:"required"`
+ GasLimit *math.HexOrDecimal256 `gencodec:"required"`
+ GasPrice *math.HexOrDecimal256 `gencodec:"required"`
+ Nonce *math.HexOrDecimal64 `gencodec:"required"`
+ Value *math.HexOrDecimal256 `gencodec:"required"`
+ R *math.HexOrDecimal256 `gencodec:"required"`
+ S *math.HexOrDecimal256 `gencodec:"required"`
+ V *math.HexOrDecimal256 `gencodec:"required"`
+ To *common.Address `gencodec:"required"`
+ }
+ var dec ttTransaction
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Data == nil {
+ return errors.New("missing required field 'data' for ttTransaction")
+ }
+ t.Data = dec.Data
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'gasLimit' for ttTransaction")
+ }
+ t.GasLimit = (*big.Int)(dec.GasLimit)
+ if dec.GasPrice == nil {
+ return errors.New("missing required field 'gasPrice' for ttTransaction")
+ }
+ t.GasPrice = (*big.Int)(dec.GasPrice)
+ if dec.Nonce == nil {
+ return errors.New("missing required field 'nonce' for ttTransaction")
+ }
+ t.Nonce = uint64(*dec.Nonce)
+ if dec.Value == nil {
+ return errors.New("missing required field 'value' for ttTransaction")
+ }
+ t.Value = (*big.Int)(dec.Value)
+ if dec.R == nil {
+ return errors.New("missing required field 'r' for ttTransaction")
+ }
+ t.R = (*big.Int)(dec.R)
+ if dec.S == nil {
+ return errors.New("missing required field 's' for ttTransaction")
+ }
+ t.S = (*big.Int)(dec.S)
+ if dec.V == nil {
+ return errors.New("missing required field 'v' for ttTransaction")
+ }
+ t.V = (*big.Int)(dec.V)
+ if dec.To == nil {
+ return errors.New("missing required field 'to' for ttTransaction")
+ }
+ t.To = *dec.To
+ return nil
+}
diff --git a/tests/gen_vmexec.go b/tests/gen_vmexec.go
new file mode 100644
index 0000000000..dd2d3d94e7
--- /dev/null
+++ b/tests/gen_vmexec.go
@@ -0,0 +1,88 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package tests
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
+)
+
+var _ = (*vmExecMarshaling)(nil)
+
+func (v vmExec) MarshalJSON() ([]byte, error) {
+ type vmExec struct {
+ Address common.UnprefixedAddress `json:"address" gencodec:"required"`
+ Caller common.UnprefixedAddress `json:"caller" gencodec:"required"`
+ Origin common.UnprefixedAddress `json:"origin" gencodec:"required"`
+ Code hexutil.Bytes `json:"code" gencodec:"required"`
+ Data hexutil.Bytes `json:"data" gencodec:"required"`
+ Value *math.HexOrDecimal256 `json:"value" gencodec:"required"`
+ GasLimit math.HexOrDecimal64 `json:"gas" gencodec:"required"`
+ GasPrice *math.HexOrDecimal256 `json:"gasPrice" gencodec:"required"`
+ }
+ var enc vmExec
+ enc.Address = common.UnprefixedAddress(v.Address)
+ enc.Caller = common.UnprefixedAddress(v.Caller)
+ enc.Origin = common.UnprefixedAddress(v.Origin)
+ enc.Code = v.Code
+ enc.Data = v.Data
+ enc.Value = (*math.HexOrDecimal256)(v.Value)
+ enc.GasLimit = math.HexOrDecimal64(v.GasLimit)
+ enc.GasPrice = (*math.HexOrDecimal256)(v.GasPrice)
+ return json.Marshal(&enc)
+}
+
+func (v *vmExec) UnmarshalJSON(input []byte) error {
+ type vmExec struct {
+ Address *common.UnprefixedAddress `json:"address" gencodec:"required"`
+ Caller *common.UnprefixedAddress `json:"caller" gencodec:"required"`
+ Origin *common.UnprefixedAddress `json:"origin" gencodec:"required"`
+ Code hexutil.Bytes `json:"code" gencodec:"required"`
+ Data hexutil.Bytes `json:"data" gencodec:"required"`
+ Value *math.HexOrDecimal256 `json:"value" gencodec:"required"`
+ GasLimit *math.HexOrDecimal64 `json:"gas" gencodec:"required"`
+ GasPrice *math.HexOrDecimal256 `json:"gasPrice" gencodec:"required"`
+ }
+ var dec vmExec
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Address == nil {
+ return errors.New("missing required field 'address' for vmExec")
+ }
+ v.Address = common.Address(*dec.Address)
+ if dec.Caller == nil {
+ return errors.New("missing required field 'caller' for vmExec")
+ }
+ v.Caller = common.Address(*dec.Caller)
+ if dec.Origin == nil {
+ return errors.New("missing required field 'origin' for vmExec")
+ }
+ v.Origin = common.Address(*dec.Origin)
+ if dec.Code == nil {
+ return errors.New("missing required field 'code' for vmExec")
+ }
+ v.Code = dec.Code
+ if dec.Data == nil {
+ return errors.New("missing required field 'data' for vmExec")
+ }
+ v.Data = dec.Data
+ if dec.Value == nil {
+ return errors.New("missing required field 'value' for vmExec")
+ }
+ v.Value = (*big.Int)(dec.Value)
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'gas' for vmExec")
+ }
+ v.GasLimit = uint64(*dec.GasLimit)
+ if dec.GasPrice == nil {
+ return errors.New("missing required field 'gasPrice' for vmExec")
+ }
+ v.GasPrice = (*big.Int)(dec.GasPrice)
+ return nil
+}
diff --git a/tests/init.go b/tests/init.go
deleted file mode 100644
index 7b0924bc38..0000000000
--- a/tests/init.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// Package tests implements execution of Ethereum JSON tests.
-package tests
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "path/filepath"
-)
-
-var (
- baseDir = filepath.Join(".", "files")
- blockTestDir = filepath.Join(baseDir, "BlockchainTests")
- stateTestDir = filepath.Join(baseDir, "StateTests")
- transactionTestDir = filepath.Join(baseDir, "TransactionTests")
- vmTestDir = filepath.Join(baseDir, "VMTests")
- rlpTestDir = filepath.Join(baseDir, "RLPTests")
-
- BlockSkipTests = []string{
- // These tests are not valid, as they are out of scope for RLP and
- // the consensus protocol.
- "BLOCK__RandomByteAtTheEnd",
- "TRANSCT__RandomByteAtTheEnd",
- "BLOCK__ZeroByteAtTheEnd",
- "TRANSCT__ZeroByteAtTheEnd",
-
- "ChainAtoChainB_blockorder2",
- "ChainAtoChainB_blockorder1",
-
- "GasLimitHigherThan2p63m1", // not yet ;)
- "SuicideIssue", // fails genesis check
- }
-
- /* Go client does not support transaction (account) nonces above 2^64. This
- technically breaks consensus but is regarded as "reasonable
- engineering constraint" as accounts cannot easily reach such high
- nonce values in practice
- */
- TransSkipTests = []string{
- "TransactionWithHihghNonce256",
- "Vitalik_15",
- "Vitalik_16",
- "Vitalik_17",
- }
- StateSkipTests = []string{}
- VmSkipTests = []string{}
-)
-
-func readJson(reader io.Reader, value interface{}) error {
- data, err := ioutil.ReadAll(reader)
- if err != nil {
- return fmt.Errorf("error reading JSON file: %v", err)
- }
- if err = json.Unmarshal(data, &value); err != nil {
- if syntaxerr, ok := err.(*json.SyntaxError); ok {
- line := findLine(data, syntaxerr.Offset)
- return fmt.Errorf("JSON syntax error at line %v: %v", line, err)
- }
- return fmt.Errorf("JSON unmarshal error: %v", err)
- }
- return nil
-}
-
-func readJsonHttp(uri string, value interface{}) error {
- resp, err := http.Get(uri)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return readJson(resp.Body, value)
-}
-
-func readJsonFile(fn string, value interface{}) error {
- file, err := os.Open(fn)
- if err != nil {
- return err
- }
- defer file.Close()
-
- err = readJson(file, value)
- if err != nil {
- return fmt.Errorf("%s in file %s", err.Error(), fn)
- }
- return nil
-}
-
-// findLine returns the line number for the given offset into data.
-func findLine(data []byte, offset int64) (line int) {
- line = 1
- for i, r := range string(data) {
- if int64(i) >= offset {
- return
- }
- if r == '\n' {
- line++
- }
- }
- return
-}
diff --git a/tests/init_test.go b/tests/init_test.go
new file mode 100644
index 0000000000..0adbb533dd
--- /dev/null
+++ b/tests/init_test.go
@@ -0,0 +1,263 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package tests
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "regexp"
+ "sort"
+ "strings"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/params"
+)
+
+var (
+ baseDir = filepath.Join(".", "testdata")
+ blockTestDir = filepath.Join(baseDir, "BlockchainTests")
+ stateTestDir = filepath.Join(baseDir, "GeneralStateTests")
+ transactionTestDir = filepath.Join(baseDir, "TransactionTests")
+ vmTestDir = filepath.Join(baseDir, "VMTests")
+ rlpTestDir = filepath.Join(baseDir, "RLPTests")
+)
+
+func readJson(reader io.Reader, value interface{}) error {
+ data, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return fmt.Errorf("error reading JSON file: %v", err)
+ }
+ if err = json.Unmarshal(data, &value); err != nil {
+ if syntaxerr, ok := err.(*json.SyntaxError); ok {
+ line := findLine(data, syntaxerr.Offset)
+ return fmt.Errorf("JSON syntax error at line %v: %v", line, err)
+ }
+ return err
+ }
+ return nil
+}
+
+func readJsonFile(fn string, value interface{}) error {
+ file, err := os.Open(fn)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ err = readJson(file, value)
+ if err != nil {
+ return fmt.Errorf("%s in file %s", err.Error(), fn)
+ }
+ return nil
+}
+
+// findLine returns the line number for the given offset into data.
+func findLine(data []byte, offset int64) (line int) {
+ line = 1
+ for i, r := range string(data) {
+ if int64(i) >= offset {
+ return
+ }
+ if r == '\n' {
+ line++
+ }
+ }
+ return
+}
+
+// testMatcher controls skipping and chain config assignment to tests.
+type testMatcher struct {
+ configpat []testConfig
+ failpat []testFailure
+ skiploadpat []*regexp.Regexp
+ skipshortpat []*regexp.Regexp
+}
+
+type testConfig struct {
+ p *regexp.Regexp
+ config params.ChainConfig
+}
+
+type testFailure struct {
+ p *regexp.Regexp
+ reason string
+}
+
+// skipShortMode skips tests matching when the -short flag is used.
+func (tm *testMatcher) skipShortMode(pattern string) {
+ tm.skipshortpat = append(tm.skipshortpat, regexp.MustCompile(pattern))
+}
+
+// skipLoad skips JSON loading of tests matching the pattern.
+func (tm *testMatcher) skipLoad(pattern string) {
+ tm.skiploadpat = append(tm.skiploadpat, regexp.MustCompile(pattern))
+}
+
+// fails adds an expected failure for tests matching the pattern.
+func (tm *testMatcher) fails(pattern string, reason string) {
+ if reason == "" {
+ panic("empty fail reason")
+ }
+ tm.failpat = append(tm.failpat, testFailure{regexp.MustCompile(pattern), reason})
+}
+
+// config defines chain config for tests matching the pattern.
+func (tm *testMatcher) config(pattern string, cfg params.ChainConfig) {
+ tm.configpat = append(tm.configpat, testConfig{regexp.MustCompile(pattern), cfg})
+}
+
+// findSkip matches name against test skip patterns.
+func (tm *testMatcher) findSkip(name string) (reason string, skipload bool) {
+ if testing.Short() {
+ for _, re := range tm.skipshortpat {
+ if re.MatchString(name) {
+ return "skipped in -short mode", false
+ }
+ }
+ }
+ for _, re := range tm.skiploadpat {
+ if re.MatchString(name) {
+ return "skipped by skipLoad", true
+ }
+ }
+ return "", false
+}
+
+// findConfig returns the chain config matching defined patterns.
+func (tm *testMatcher) findConfig(name string) *params.ChainConfig {
+ // TODO(fjl): name can be derived from testing.T when min Go version is 1.8
+ for _, m := range tm.configpat {
+ if m.p.MatchString(name) {
+ return &m.config
+ }
+ }
+ return new(params.ChainConfig)
+}
+
+// checkFailure checks whether a failure is expected.
+func (tm *testMatcher) checkFailure(t *testing.T, name string, err error) error {
+ // TODO(fjl): name can be derived from t when min Go version is 1.8
+ failReason := ""
+ for _, m := range tm.failpat {
+ if m.p.MatchString(name) {
+ failReason = m.reason
+ break
+ }
+ }
+ if failReason != "" {
+ t.Logf("expected failure: %s", failReason)
+ if err != nil {
+ t.Logf("error: %v", err)
+ return nil
+ } else {
+ return fmt.Errorf("test succeeded unexpectedly")
+ }
+ }
+ return err
+}
+
+// walk invokes its runTest argument for all subtests in the given directory.
+//
+// runTest should be a function of type func(t *testing.T, name string, x ),
+// where TestType is the type of the test contained in test files.
+func (tm *testMatcher) walk(t *testing.T, dir string, runTest interface{}) {
+ // Walk the directory.
+ dirinfo, err := os.Stat(dir)
+ if os.IsNotExist(err) || !dirinfo.IsDir() {
+ fmt.Fprintf(os.Stderr, "can't find test files in %s, did you clone the tests submodule?\n", dir)
+ t.Skip("missing test files")
+ }
+ err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ name := filepath.ToSlash(strings.TrimPrefix(path, dir+string(filepath.Separator)))
+ if info.IsDir() {
+ if _, skipload := tm.findSkip(name + "/"); skipload {
+ return filepath.SkipDir
+ }
+ return nil
+ }
+ if filepath.Ext(path) == ".json" {
+ t.Run(name, func(t *testing.T) { tm.runTestFile(t, path, name, runTest) })
+ }
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func (tm *testMatcher) runTestFile(t *testing.T, path, name string, runTest interface{}) {
+ if r, _ := tm.findSkip(name); r != "" {
+ t.Skip(r)
+ }
+ t.Parallel()
+
+ // Load the file as map[string].
+ m := makeMapFromTestFunc(runTest)
+ if err := readJsonFile(path, m.Addr().Interface()); err != nil {
+ t.Fatal(err)
+ }
+
+ // Run all tests from the map. Don't wrap in a subtest if there is only one test in the file.
+ keys := sortedMapKeys(m)
+ if len(keys) == 1 {
+ runTestFunc(runTest, t, name, m, keys[0])
+ } else {
+ for _, key := range keys {
+ name := name + "/" + key
+ t.Run(key, func(t *testing.T) {
+ if r, _ := tm.findSkip(name); r != "" {
+ t.Skip(r)
+ }
+ runTestFunc(runTest, t, name, m, key)
+ })
+ }
+ }
+}
+
+func makeMapFromTestFunc(f interface{}) reflect.Value {
+ stringT := reflect.TypeOf("")
+ testingT := reflect.TypeOf((*testing.T)(nil))
+ ftyp := reflect.TypeOf(f)
+ if ftyp.Kind() != reflect.Func || ftyp.NumIn() != 3 || ftyp.NumOut() != 0 || ftyp.In(0) != testingT || ftyp.In(1) != stringT {
+ panic(fmt.Sprintf("bad test function type: want func(*testing.T, string, ), have %s", ftyp))
+ }
+ testType := ftyp.In(2)
+ mp := reflect.New(reflect.MapOf(stringT, testType))
+ return mp.Elem()
+}
+
+func sortedMapKeys(m reflect.Value) []string {
+ keys := make([]string, m.Len())
+ for i, k := range m.MapKeys() {
+ keys[i] = k.String()
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+func runTestFunc(runTest interface{}, t *testing.T, name string, m reflect.Value, key string) {
+ reflect.ValueOf(runTest).Call([]reflect.Value{
+ reflect.ValueOf(t),
+ reflect.ValueOf(name),
+ m.MapIndex(reflect.ValueOf(key)),
+ })
+}
diff --git a/tests/rlp_test.go b/tests/rlp_test.go
index 2469ce0dbc..1601625df5 100644
--- a/tests/rlp_test.go
+++ b/tests/rlp_test.go
@@ -17,20 +17,15 @@
package tests
import (
- "path/filepath"
"testing"
)
func TestRLP(t *testing.T) {
- err := RunRLPTest(filepath.Join(rlpTestDir, "rlptest.json"), nil)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestRLP_invalid(t *testing.T) {
- err := RunRLPTest(filepath.Join(rlpTestDir, "invalidRLPTest.json"), nil)
- if err != nil {
- t.Fatal(err)
- }
+ t.Parallel()
+ tm := new(testMatcher)
+ tm.walk(t, rlpTestDir, func(t *testing.T, name string, test *RLPTest) {
+ if err := tm.checkFailure(t, name, test.Run()); err != nil {
+ t.Error(err)
+ }
+ })
}
diff --git a/tests/rlp_test_util.go b/tests/rlp_test_util.go
index ac53a4f52c..58ef8a6428 100644
--- a/tests/rlp_test_util.go
+++ b/tests/rlp_test_util.go
@@ -21,9 +21,7 @@ import (
"encoding/hex"
"errors"
"fmt"
- "io"
"math/big"
- "os"
"strings"
"github.com/ethereum/go-ethereum/rlp"
@@ -44,33 +42,6 @@ type RLPTest struct {
Out string
}
-// RunRLPTest runs the tests in the given file, skipping tests by name.
-func RunRLPTest(file string, skip []string) error {
- f, err := os.Open(file)
- if err != nil {
- return err
- }
- defer f.Close()
- return RunRLPTestWithReader(f, skip)
-}
-
-// RunRLPTest runs the tests encoded in r, skipping tests by name.
-func RunRLPTestWithReader(r io.Reader, skip []string) error {
- var tests map[string]*RLPTest
- if err := readJson(r, &tests); err != nil {
- return err
- }
- for _, s := range skip {
- delete(tests, s)
- }
- for name, test := range tests {
- if err := test.Run(); err != nil {
- return fmt.Errorf("test %q failed: %v", name, err)
- }
- }
- return nil
-}
-
// Run executes the test.
func (t *RLPTest) Run() error {
outb, err := hex.DecodeString(t.Out)
diff --git a/tests/state_test.go b/tests/state_test.go
index 29180942b2..e4e691589e 100644
--- a/tests/state_test.go
+++ b/tests/state_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The go-ethereum Authors
+// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -17,970 +17,72 @@
package tests
import (
- "math/big"
- "os"
- "path/filepath"
+ "bytes"
+ "fmt"
+ "reflect"
"testing"
- "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/core/vm"
)
-func BenchmarkStateCall1024(b *testing.B) {
- fn := filepath.Join(stateTestDir, "stCallCreateCallCodeTest.json")
- if err := BenchVmTest(fn, bconf{"Call1024BalanceTooLow", true, os.Getenv("JITVM") == "true"}, b); err != nil {
- b.Error(err)
- }
-}
+func TestState(t *testing.T) {
+ t.Parallel()
-func TestStateSystemOperations(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
+ st := new(testMatcher)
+ // Long tests:
+ st.skipShortMode(`^stQuadraticComplexityTest/`)
+ // Broken tests:
+ st.skipLoad(`^stTransactionTest/OverflowGasRequire\.json`) // gasLimit > 256 bits
+ st.skipLoad(`^stStackTests/shallowStackOK\.json`) // bad hex encoding
+ st.skipLoad(`^stTransactionTest/zeroSigTransa[^/]*\.json`) // EIP-86 is not supported yet
+ // Expected failures:
+ st.fails(`^stCallCreateCallCodeTest/createJS_ExampleContract\.json`, "bug in test")
+ st.fails(`^stCodeSizeLimit/codesizeOOGInvalidSize\.json/(Frontier|Homestead)`,
+ "code size limit implementation is not conditional on fork")
+ st.fails(`^stRevertTest/RevertDepthCreateAddressCollision\.json/EIP15[08]/[67]`, "bug in test")
+ st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/EIP158`, "bug in test")
+ st.fails(`^stRevertTest/RevertPrefoundEmptyOOG\.json/EIP158`, "bug in test")
- fn := filepath.Join(stateTestDir, "stSystemOperationsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateExample(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stExample.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStatePreCompiledContracts(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stPreCompiledContracts.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateRecursiveCreate(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stRecursiveCreate.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateSpecial(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stSpecialTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateRefund(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stRefundTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateBlockHash(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stBlockHashTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateInitCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stInitCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateLog(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stLogTests.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateTransaction(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stTransactionTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateTransition(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stTransitionTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestCallCreateCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stCallCreateCallCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestCallCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stCallCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestMemory(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stMemoryTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestMemoryStress(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "stMemoryStressTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestQuadraticComplexity(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "stQuadraticComplexityTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestSolidity(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stSolidityTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestWallet(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fn := filepath.Join(stateTestDir, "stWalletTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestStateTestsRandom(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
-
- fns, _ := filepath.Glob("./files/StateTests/RandomTests/*")
- for _, fn := range fns {
- t.Log("running:", fn)
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(fn, err)
+ st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) {
+ for _, subtest := range test.Subtests() {
+ subtest := subtest
+ key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index)
+ name := name + "/" + key
+ t.Run(key, func(t *testing.T) {
+ if subtest.Fork == "Metropolis" {
+ t.Skip("metropolis not supported yet")
+ }
+ withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error {
+ return st.checkFailure(t, name, test.Run(subtest, vmconfig))
+ })
+ })
}
- }
+ })
}
-// homestead tests
-func TestHomesteadDelegateCall(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(1150000),
- }
+// Transactions with gasLimit above this value will not get a VM trace on failure.
+const traceErrorLimit = 400000
- fn := filepath.Join(stateTestDir, "Homestead", "stDelegatecallTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStateSystemOperations(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stSystemOperationsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStatePreCompiledContracts(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stPreCompiledContracts.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStateRecursiveCreate(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stSpecialTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStateRefund(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stRefundTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStateInitCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stInitCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStateLog(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stLogTests.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadStateTransaction(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stTransactionTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadCallCreateCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stCallCreateCallCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadCallCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stCallCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadMemory(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stMemoryTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadMemoryStress(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "Homestead", "stMemoryStressTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadQuadraticComplexity(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "Homestead", "stQuadraticComplexityTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadWallet(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stWalletTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadDelegateCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stCallDelegateCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadDelegateCodesCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stCallDelegateCodesCallCode.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestHomesteadBounds(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- }
-
- fn := filepath.Join(stateTestDir, "Homestead", "stBoundsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-// EIP150 tests
-func TestEIP150Specific(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "stEIPSpecificTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150SingleCodeGasPrice(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "stEIPSingleCodeGasPrices.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150MemExpandingCalls(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "stMemExpandingEIPCalls.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStateSystemOperations(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stSystemOperationsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStatePreCompiledContracts(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stPreCompiledContracts.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStateRecursiveCreate(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stSpecialTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStateRefund(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stRefundTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStateInitCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stInitCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStateLog(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stLogTests.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadStateTransaction(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stTransactionTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadCallCreateCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallCreateCallCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadCallCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadMemory(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stMemoryTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadMemoryStress(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stMemoryStressTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadQuadraticComplexity(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stQuadraticComplexityTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadWallet(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stWalletTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadDelegateCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallDelegateCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadDelegateCodesCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallDelegateCodesCallCode.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP150HomesteadBounds(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- }
-
- fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stBoundsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-// EIP158 tests
-func TestEIP158Create(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "stCreateTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158Specific(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "stEIP158SpecificTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158NonZeroCalls(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "stNonZeroCallsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158ZeroCalls(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "stZeroCallsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158_150Specific(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "EIP150", "stEIPSpecificTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158_150SingleCodeGasPrice(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "EIP150", "stEIPsingleCodeGasPrices.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158_150MemExpandingCalls(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "EIP150", "stMemExpandingEIPCalls.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStateSystemOperations(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stSystemOperationsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStatePreCompiledContracts(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stPreCompiledContracts.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStateRecursiveCreate(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stSpecialTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStateRefund(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stRefundTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStateInitCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stInitCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStateLog(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stLogTests.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadStateTransaction(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stTransactionTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadCallCreateCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stCallCreateCallCodeTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadCallCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stCallCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadMemory(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stMemoryTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadMemoryStress(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stMemoryStressTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadQuadraticComplexity(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- if os.Getenv("TEST_VM_COMPLEX") == "" {
- t.Skip()
- }
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stQuadraticComplexityTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadWallet(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stWalletTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadDelegateCodes(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stCallDelegateCodes.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadDelegateCodesCallCode(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stCallDelegateCodesCallCode.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestEIP158HomesteadBounds(t *testing.T) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: new(big.Int),
- EIP150Block: big.NewInt(2457000),
- EIP158Block: params.MainnetChainConfig.EIP158Block,
- }
-
- fn := filepath.Join(stateTestDir, "EIP158", "Homestead", "stBoundsTest.json")
- if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
- t.Error(err)
+func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) {
+ err := test(vm.Config{})
+ if err == nil {
+ return
+ }
+ t.Error(err)
+ if gasLimit > traceErrorLimit {
+ t.Log("gas limit too high for EVM trace")
+ return
+ }
+ tracer := vm.NewStructLogger(nil)
+ err2 := test(vm.Config{Debug: true, Tracer: tracer})
+ if !reflect.DeepEqual(err, err2) {
+ t.Errorf("different error for second run: %v", err2)
+ }
+ buf := new(bytes.Buffer)
+ vm.WriteTrace(buf, tracer.StructLogs())
+ if buf.Len() == 0 {
+ t.Log("no EVM operation logs generated")
+ } else {
+ t.Log("EVM operation log:\n" + buf.String())
}
}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 58acdd488b..fb74f5df09 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The go-ethereum Authors
+// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -18,180 +18,296 @@ package tests
import (
"bytes"
+ "encoding/hex"
+ "encoding/json"
"fmt"
- "io"
- "strconv"
+ "math/big"
+ "reflect"
"strings"
- "testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
-func RunStateTestWithReader(chainConfig *params.ChainConfig, r io.Reader, skipTests []string) error {
- tests := make(map[string]VmTest)
- if err := readJson(r, &tests); err != nil {
- return err
- }
-
- if err := runStateTests(chainConfig, tests, skipTests); err != nil {
- return err
- }
-
- return nil
+// This table defines supported forks and their chain config.
+var stateTestForks = map[string]*params.ChainConfig{
+ "Frontier": ¶ms.ChainConfig{
+ ChainId: big.NewInt(1),
+ },
+ "Homestead": ¶ms.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ ChainId: big.NewInt(1),
+ },
+ "EIP150": ¶ms.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ ChainId: big.NewInt(1),
+ },
+ "EIP158": ¶ms.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ ChainId: big.NewInt(1),
+ },
+ "Metropolis": ¶ms.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ MetropolisBlock: big.NewInt(0),
+ ChainId: big.NewInt(1),
+ },
}
-func RunStateTest(chainConfig *params.ChainConfig, p string, skipTests []string) error {
- tests := make(map[string]VmTest)
- if err := readJsonFile(p, &tests); err != nil {
- return err
- }
-
- if err := runStateTests(chainConfig, tests, skipTests); err != nil {
- return err
- }
-
- return nil
-
+// StateTest checks transaction processing without block context.
+// See https://github.com/ethereum/EIPs/issues/176 for the test format specification.
+type StateTest struct {
+ json stJSON
}
-func BenchStateTest(chainConfig *params.ChainConfig, p string, conf bconf, b *testing.B) error {
- tests := make(map[string]VmTest)
- if err := readJsonFile(p, &tests); err != nil {
- return err
+// StateSubtest selects a specific configuration of a General State Test.
+type StateSubtest struct {
+ Fork string
+ Index int
+}
+
+func (t *StateTest) UnmarshalJSON(in []byte) error {
+ return json.Unmarshal(in, &t.json)
+}
+
+type stJSON struct {
+ Env stEnv `json:"env"`
+ Pre core.GenesisAlloc `json:"pre"`
+ Tx stTransaction `json:"transaction"`
+ Out hexutil.Bytes `json:"out"`
+ Post map[string][]stPostState `json:"post"`
+}
+
+type stPostState struct {
+ Root common.UnprefixedHash `json:"hash"`
+ Logs *[]stLog `json:"logs"`
+ Indexes struct {
+ Data int `json:"data"`
+ Gas int `json:"gas"`
+ Value int `json:"value"`
}
- test, ok := tests[conf.name]
+}
+
+//go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
+
+type stEnv struct {
+ Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
+ Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"`
+ GasLimit *big.Int `json:"currentGasLimit" gencodec:"required"`
+ Number uint64 `json:"currentNumber" gencodec:"required"`
+ Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
+}
+
+type stEnvMarshaling struct {
+ Coinbase common.UnprefixedAddress
+ Difficulty *math.HexOrDecimal256
+ GasLimit *math.HexOrDecimal256
+ Number math.HexOrDecimal64
+ Timestamp math.HexOrDecimal64
+}
+
+//go:generate gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go
+
+type stTransaction struct {
+ GasPrice *big.Int `json:"gasPrice"`
+ Nonce uint64 `json:"nonce"`
+ To string `json:"to"`
+ Data []string `json:"data"`
+ GasLimit []uint64 `json:"gasLimit"`
+ Value []string `json:"value"`
+ PrivateKey []byte `json:"secretKey"`
+}
+
+type stTransactionMarshaling struct {
+ GasPrice *math.HexOrDecimal256
+ Nonce math.HexOrDecimal64
+ GasLimit []math.HexOrDecimal64
+ PrivateKey hexutil.Bytes
+}
+
+//go:generate gencodec -type stLog -field-override stLogMarshaling -out gen_stlog.go
+
+type stLog struct {
+ Address common.Address `json:"address"`
+ Data []byte `json:"data"`
+ Topics []common.Hash `json:"topics"`
+ Bloom string `json:"bloom"`
+}
+
+type stLogMarshaling struct {
+ Address common.UnprefixedAddress
+ Data hexutil.Bytes
+ Topics []common.UnprefixedHash
+}
+
+// Subtests returns all valid subtests of the test.
+func (t *StateTest) Subtests() []StateSubtest {
+ var sub []StateSubtest
+ for fork, pss := range t.json.Post {
+ for i, _ := range pss {
+ sub = append(sub, StateSubtest{fork, i})
+ }
+ }
+ return sub
+}
+
+// Run executes a specific subtest.
+func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error {
+ config, ok := stateTestForks[subtest.Fork]
if !ok {
- return fmt.Errorf("test not found: %s", conf.name)
+ return fmt.Errorf("no config for fork %q", subtest.Fork)
}
-
- // XXX Yeah, yeah...
- env := make(map[string]string)
- env["currentCoinbase"] = test.Env.CurrentCoinbase
- env["currentDifficulty"] = test.Env.CurrentDifficulty
- env["currentGasLimit"] = test.Env.CurrentGasLimit
- env["currentNumber"] = test.Env.CurrentNumber
- env["previousHash"] = test.Env.PreviousHash
- if n, ok := test.Env.CurrentTimestamp.(float64); ok {
- env["currentTimestamp"] = strconv.Itoa(int(n))
- } else {
- env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
- }
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- benchStateTest(chainConfig, test, env, b)
- }
-
- return nil
-}
-
-func benchStateTest(chainConfig *params.ChainConfig, test VmTest, env map[string]string, b *testing.B) {
- b.StopTimer()
+ block, _ := t.genesis(config).ToBlock()
db, _ := ethdb.NewMemDatabase()
- statedb := makePreState(db, test.Pre)
- b.StartTimer()
+ statedb := makePreState(db, t.json.Pre)
- RunState(chainConfig, statedb, db, env, test.Exec)
-}
-
-func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, skipTests []string) error {
- skipTest := make(map[string]bool, len(skipTests))
- for _, name := range skipTests {
- skipTest[name] = true
- }
-
- for name, test := range tests {
- if skipTest[name] /*|| name != "JUMPDEST_Attack"*/ {
- log.Info(fmt.Sprint("Skipping state test", name))
- continue
- }
-
- //fmt.Println("StateTest:", name)
- if err := runStateTest(chainConfig, test); err != nil {
- return fmt.Errorf("%s: %s\n", name, err.Error())
- }
-
- //log.Info(fmt.Sprint("State test passed: ", name))
- //fmt.Println(string(statedb.Dump()))
- }
- return nil
-
-}
-
-func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
- db, _ := ethdb.NewMemDatabase()
- statedb := makePreState(db, test.Pre)
-
- // XXX Yeah, yeah...
- env := make(map[string]string)
- env["currentCoinbase"] = test.Env.CurrentCoinbase
- env["currentDifficulty"] = test.Env.CurrentDifficulty
- env["currentGasLimit"] = test.Env.CurrentGasLimit
- env["currentNumber"] = test.Env.CurrentNumber
- env["previousHash"] = test.Env.PreviousHash
- if n, ok := test.Env.CurrentTimestamp.(float64); ok {
- env["currentTimestamp"] = strconv.Itoa(int(n))
- } else {
- env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
- }
-
- ret, logs, root, _ := RunState(chainConfig, statedb, db, env, test.Transaction)
-
- // Return value:
- var rexp []byte
- if strings.HasPrefix(test.Out, "#") {
- n, _ := strconv.Atoi(test.Out[1:])
- rexp = make([]byte, n)
- } else {
- rexp = common.FromHex(test.Out)
- }
- if !bytes.Equal(rexp, ret) {
- return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
- }
- // Post state content:
- for addr, account := range test.Post {
- address := common.HexToAddress(addr)
- if !statedb.Exist(address) {
- return fmt.Errorf("did not find expected post-state account: %s", addr)
- }
- if balance := statedb.GetBalance(address); balance.Cmp(math.MustParseBig256(account.Balance)) != 0 {
- return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], math.MustParseBig256(account.Balance), balance)
- }
- if nonce := statedb.GetNonce(address); nonce != math.MustParseUint64(account.Nonce) {
- return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", address[:4], account.Nonce, nonce)
- }
- for addr, value := range account.Storage {
- v := statedb.GetState(address, common.HexToHash(addr))
- vexp := common.HexToHash(value)
- if v != vexp {
- return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave: %x\n(%v %v)\n", address[:4], addr, vexp, v, vexp.Big(), v.Big())
- }
- }
- }
- // Root:
- if common.HexToHash(test.PostStateRoot) != root {
- return fmt.Errorf("Post state root error. Expected: %s have: %x", test.PostStateRoot, root)
- }
- // Logs:
- return checkLogs(test.Logs, logs)
-}
-
-func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, db ethdb.Database, env, tx map[string]string) ([]byte, []*types.Log, common.Hash, error) {
- environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx)
- gaspool := new(core.GasPool).AddGas(math.MustParseBig256(env["currentGasLimit"]))
-
- snapshot := statedb.Snapshot()
- ret, _, err := core.ApplyMessage(environment, msg, gaspool)
+ post := t.json.Post[subtest.Fork][subtest.Index]
+ msg, err := t.json.Tx.toMessage(post)
if err != nil {
+ return err
+ }
+ context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase)
+ context.GetHash = vmTestBlockHash
+ evm := vm.NewEVM(context, statedb, config, vmconfig)
+
+ gaspool := new(core.GasPool)
+ gaspool.AddGas(block.GasLimit())
+ snapshot := statedb.Snapshot()
+ if _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
statedb.RevertToSnapshot(snapshot)
}
- root, _ := statedb.CommitTo(db, chainConfig.IsEIP158(environment.Context.BlockNumber))
- return ret, statedb.Logs(), root, err
+ if post.Logs != nil {
+ if err := checkLogs(statedb.Logs(), *post.Logs); err != nil {
+ return err
+ }
+ }
+ root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number()))
+ if root != common.Hash(post.Root) {
+ return fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root)
+ }
+ // TODO(fjl): check return data
+ return nil
+}
+
+func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
+ return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas]
+}
+
+func makePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
+ sdb := state.NewDatabase(db)
+ statedb, _ := state.New(common.Hash{}, sdb)
+ for addr, a := range accounts {
+ statedb.SetCode(addr, a.Code)
+ statedb.SetNonce(addr, a.Nonce)
+ statedb.SetBalance(addr, a.Balance)
+ for k, v := range a.Storage {
+ statedb.SetState(addr, k, v)
+ }
+ }
+ // Commit and re-open to start with a clean state.
+ root, _ := statedb.CommitTo(db, false)
+ statedb, _ = state.New(root, sdb)
+ return statedb
+}
+
+func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis {
+ return &core.Genesis{
+ Config: config,
+ Coinbase: t.json.Env.Coinbase,
+ Difficulty: t.json.Env.Difficulty,
+ GasLimit: t.json.Env.GasLimit.Uint64(),
+ Number: t.json.Env.Number,
+ Timestamp: t.json.Env.Timestamp,
+ Alloc: t.json.Pre,
+ }
+}
+
+func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) {
+ // Derive sender from private key if present.
+ var from common.Address
+ if len(tx.PrivateKey) > 0 {
+ key, err := crypto.ToECDSA(tx.PrivateKey)
+ if err != nil {
+ return nil, fmt.Errorf("invalid private key: %v", err)
+ }
+ from = crypto.PubkeyToAddress(key.PublicKey)
+ }
+ // Parse recipient if present.
+ var to *common.Address
+ if tx.To != "" {
+ to = new(common.Address)
+ if err := to.UnmarshalText([]byte(tx.To)); err != nil {
+ return nil, fmt.Errorf("invalid to address: %v", err)
+ }
+ }
+
+ // Get values specific to this post state.
+ if ps.Indexes.Data > len(tx.Data) {
+ return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data)
+ }
+ if ps.Indexes.Value > len(tx.Value) {
+ return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value)
+ }
+ if ps.Indexes.Gas > len(tx.GasLimit) {
+ return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas)
+ }
+ dataHex := tx.Data[ps.Indexes.Data]
+ valueHex := tx.Value[ps.Indexes.Value]
+ gasLimit := tx.GasLimit[ps.Indexes.Gas]
+ // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203
+ value := new(big.Int)
+ if valueHex != "0x" {
+ v, ok := math.ParseBig256(valueHex)
+ if !ok {
+ return nil, fmt.Errorf("invalid tx value %q", valueHex)
+ }
+ value = v
+ }
+ data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x"))
+ if err != nil {
+ return nil, fmt.Errorf("invalid tx data %q", dataHex)
+ }
+
+ msg := types.NewMessage(from, to, tx.Nonce, value, new(big.Int).SetUint64(gasLimit), tx.GasPrice, data, true)
+ return msg, nil
+}
+
+func checkLogs(have []*types.Log, want []stLog) error {
+ if len(have) != len(want) {
+ return fmt.Errorf("logs length mismatch: got %d, want %d", len(have), len(want))
+ }
+ for i := range have {
+ if have[i].Address != want[i].Address {
+ return fmt.Errorf("log address %d: got %x, want %x", i, have[i].Address, want[i].Address)
+ }
+ if !bytes.Equal(have[i].Data, want[i].Data) {
+ return fmt.Errorf("log data %d: got %x, want %x", i, have[i].Data, want[i].Data)
+ }
+ if !reflect.DeepEqual(have[i].Topics, want[i].Topics) {
+ return fmt.Errorf("log topics %d:\ngot %x\nwant %x", i, have[i].Topics, want[i].Topics)
+ }
+ genBloom := math.PaddedBigBytes(types.LogsBloom([]*types.Log{have[i]}), 256)
+ var wantBloom types.Bloom
+ if err := hexutil.UnmarshalFixedUnprefixedText("Bloom", []byte(want[i].Bloom), wantBloom[:]); err != nil {
+ return fmt.Errorf("test log %d has invalid bloom: %v", i, err)
+ }
+ if !bytes.Equal(genBloom, wantBloom[:]) {
+ return fmt.Errorf("bloom mismatch")
+ }
+ }
+ return nil
}
diff --git a/tests/testdata b/tests/testdata
new file mode 160000
index 0000000000..f1de8c3b7f
--- /dev/null
+++ b/tests/testdata
@@ -0,0 +1 @@
+Subproject commit f1de8c3b7fa2c2c0aa281b6b3a1ad7010356c5ff
diff --git a/tests/transaction_test.go b/tests/transaction_test.go
index 317355eb34..72d43c0ece 100644
--- a/tests/transaction_test.go
+++ b/tests/transaction_test.go
@@ -18,109 +18,37 @@ package tests
import (
"math/big"
- "path/filepath"
"testing"
"github.com/ethereum/go-ethereum/params"
)
-func TestTransactions(t *testing.T) {
- config := ¶ms.ChainConfig{}
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "ttTransactionTest.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
+func TestTransaction(t *testing.T) {
+ t.Parallel()
-func TestWrongRLPTransactions(t *testing.T) {
- config := ¶ms.ChainConfig{}
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "ttWrongRLPTransaction.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func Test10MBTransactions(t *testing.T) {
- config := ¶ms.ChainConfig{}
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "tt10mbDataField.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-// homestead tests
-func TestHomesteadTransactions(t *testing.T) {
- config := ¶ms.ChainConfig{
+ txt := new(testMatcher)
+ txt.config(`^Homestead/`, params.ChainConfig{
HomesteadBlock: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "Homestead", "ttTransactionTest.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadWrongRLPTransactions(t *testing.T) {
- config := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "Homestead", "ttWrongRLPTransaction.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomestead10MBTransactions(t *testing.T) {
- config := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "Homestead", "tt10mbDataField.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestHomesteadVitalik(t *testing.T) {
- config := ¶ms.ChainConfig{
- HomesteadBlock: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "Homestead", "ttTransactionTestEip155VitaliksTests.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestTxEIP155Transaction(t *testing.T) {
- config := ¶ms.ChainConfig{
- ChainId: big.NewInt(1),
+ })
+ txt.config(`^EIP155/`, params.ChainConfig{
HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "EIP155", "ttTransactionTest.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func TestTxEIP155VitaliksTests(t *testing.T) {
- config := ¶ms.ChainConfig{
+ EIP158Block: big.NewInt(0),
ChainId: big.NewInt(1),
- HomesteadBlock: big.NewInt(0),
- EIP155Block: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "EIP155", "ttTransactionTestEip155VitaliksTests.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
-}
+ })
+ txt.config(`^Metropolis/`, params.ChainConfig{
+ HomesteadBlock: big.NewInt(0),
+ EIP150Block: big.NewInt(0),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ MetropolisBlock: big.NewInt(0),
+ })
-func TestTxEIP155VRule(t *testing.T) {
- config := ¶ms.ChainConfig{
- ChainId: big.NewInt(1),
- HomesteadBlock: big.NewInt(0),
- EIP155Block: big.NewInt(0),
- }
- err := RunTransactionTests(config, filepath.Join(transactionTestDir, "EIP155", "ttTransactionTestVRule.json"), TransSkipTests)
- if err != nil {
- t.Fatal(err)
- }
+ txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) {
+ cfg := txt.findConfig(name)
+ if err := txt.checkFailure(t, name, test.Run(cfg)); err != nil {
+ t.Error(err)
+ }
+ })
}
diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go
index 1ecc73a67c..472b3d6f24 100644
--- a/tests/transaction_test_util.go
+++ b/tests/transaction_test_util.go
@@ -20,208 +20,114 @@ import (
"bytes"
"errors"
"fmt"
- "io"
- "runtime"
+ "math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
-// Transaction Test JSON Format
-type TtTransaction struct {
- Data string
- GasLimit string
- GasPrice string
- Nonce string
- R string
- S string
- To string
- V string
- Value string
-}
-
+// TransactionTest checks RLP decoding and sender derivation of transactions.
type TransactionTest struct {
- Blocknumber string
- Rlp string
- Sender string
- Transaction TtTransaction
+ json ttJSON
}
-func RunTransactionTestsWithReader(config *params.ChainConfig, r io.Reader, skipTests []string) error {
- skipTest := make(map[string]bool, len(skipTests))
- for _, name := range skipTests {
- skipTest[name] = true
- }
-
- bt := make(map[string]TransactionTest)
- if err := readJson(r, &bt); err != nil {
- return err
- }
-
- for name, test := range bt {
- // if the test should be skipped, return
- if skipTest[name] {
- log.Info(fmt.Sprint("Skipping transaction test", name))
- return nil
- }
- // test the block
- if err := runTransactionTest(config, test); err != nil {
- return err
- }
- log.Info(fmt.Sprint("Transaction test passed: ", name))
-
- }
- return nil
+type ttJSON struct {
+ BlockNumber math.HexOrDecimal64 `json:"blockNumber"`
+ RLP hexutil.Bytes `json:"rlp"`
+ Sender hexutil.Bytes `json:"sender"`
+ Transaction *ttTransaction `json:"transaction"`
}
-func RunTransactionTests(config *params.ChainConfig, file string, skipTests []string) error {
- tests := make(map[string]TransactionTest)
- if err := readJsonFile(file, &tests); err != nil {
- return err
- }
+//go:generate gencodec -type ttTransaction -field-override ttTransactionMarshaling -out gen_tttransaction.go
- if err := runTransactionTests(config, tests, skipTests); err != nil {
- return err
- }
- return nil
+type ttTransaction struct {
+ Data []byte `gencodec:"required"`
+ GasLimit *big.Int `gencodec:"required"`
+ GasPrice *big.Int `gencodec:"required"`
+ Nonce uint64 `gencodec:"required"`
+ Value *big.Int `gencodec:"required"`
+ R *big.Int `gencodec:"required"`
+ S *big.Int `gencodec:"required"`
+ V *big.Int `gencodec:"required"`
+ To common.Address `gencodec:"required"`
}
-func runTransactionTests(config *params.ChainConfig, tests map[string]TransactionTest, skipTests []string) error {
- skipTest := make(map[string]bool, len(skipTests))
- for _, name := range skipTests {
- skipTest[name] = true
- }
-
- for name, test := range tests {
- // if the test should be skipped, return
- if skipTest[name] {
- log.Info(fmt.Sprint("Skipping transaction test", name))
- return nil
- }
-
- // test the block
- if err := runTransactionTest(config, test); err != nil {
- return fmt.Errorf("%s: %v", name, err)
- }
- log.Info(fmt.Sprint("Transaction test passed: ", name))
-
- }
- return nil
+type ttTransactionMarshaling struct {
+ Data hexutil.Bytes
+ GasLimit *math.HexOrDecimal256
+ GasPrice *math.HexOrDecimal256
+ Nonce math.HexOrDecimal64
+ Value *math.HexOrDecimal256
+ R *math.HexOrDecimal256
+ S *math.HexOrDecimal256
+ V *math.HexOrDecimal256
}
-func runTransactionTest(config *params.ChainConfig, txTest TransactionTest) (err error) {
+func (tt *TransactionTest) Run(config *params.ChainConfig) error {
tx := new(types.Transaction)
- err = rlp.DecodeBytes(mustConvertBytes(txTest.Rlp), tx)
-
- if err != nil {
- if txTest.Sender == "" {
- // RLP decoding failed and this is expected (test OK)
+ if err := rlp.DecodeBytes(tt.json.RLP, tx); err != nil {
+ if tt.json.Transaction == nil {
return nil
} else {
- // RLP decoding failed but is expected to succeed (test FAIL)
- return fmt.Errorf("RLP decoding failed when expected to succeed: %s", err)
+ return fmt.Errorf("RLP decoding failed: %v", err)
}
}
-
- validationError := verifyTxFields(config, txTest, tx)
- if txTest.Sender == "" {
- if validationError != nil {
- // RLP decoding works but validation should fail (test OK)
- return nil
- } else {
- // RLP decoding works but validation should fail (test FAIL)
- // (this should not be possible but added here for completeness)
- return errors.New("Field validations succeeded but should fail")
- }
- }
-
- if txTest.Sender != "" {
- if validationError == nil {
- // RLP decoding works and validations pass (test OK)
- return nil
- } else {
- // RLP decoding works and validations pass (test FAIL)
- return fmt.Errorf("Field validations failed after RLP decoding: %s", validationError)
- }
- }
- return errors.New("Should not happen: verify RLP decoding and field validation")
-}
-
-func verifyTxFields(chainConfig *params.ChainConfig, txTest TransactionTest, decodedTx *types.Transaction) (err error) {
- defer func() {
- if recovered := recover(); recovered != nil {
- buf := make([]byte, 64<<10)
- buf = buf[:runtime.Stack(buf, false)]
- err = fmt.Errorf("%v\n%s", recovered, buf)
- }
- }()
-
- var decodedSender common.Address
-
- signer := types.MakeSigner(chainConfig, math.MustParseBig256(txTest.Blocknumber))
- decodedSender, err = types.Sender(signer, decodedTx)
+ // Check sender derivation.
+ signer := types.MakeSigner(config, new(big.Int).SetUint64(uint64(tt.json.BlockNumber)))
+ sender, err := types.Sender(signer, tx)
if err != nil {
return err
}
-
- expectedSender := mustConvertAddress(txTest.Sender)
- if expectedSender != decodedSender {
- return fmt.Errorf("Sender mismatch: %x %x", expectedSender, decodedSender)
+ if sender != common.BytesToAddress(tt.json.Sender) {
+ return fmt.Errorf("Sender mismatch: got %x, want %x", sender, tt.json.Sender)
}
-
- expectedData := mustConvertBytes(txTest.Transaction.Data)
- if !bytes.Equal(expectedData, decodedTx.Data()) {
- return fmt.Errorf("Tx input data mismatch: %#v %#v", expectedData, decodedTx.Data())
+ // Check decoded fields.
+ err = tt.json.Transaction.verify(signer, tx)
+ if tt.json.Sender == nil && err == nil {
+ return errors.New("field validations succeeded but should fail")
}
-
- expectedGasLimit := mustConvertBigInt(txTest.Transaction.GasLimit, 16)
- if expectedGasLimit.Cmp(decodedTx.Gas()) != 0 {
- return fmt.Errorf("GasLimit mismatch: %v %v", expectedGasLimit, decodedTx.Gas())
+ if tt.json.Sender != nil && err != nil {
+ return fmt.Errorf("field validations failed after RLP decoding: %s", err)
+ }
+ return nil
+}
+
+func (tt *ttTransaction) verify(signer types.Signer, tx *types.Transaction) error {
+ if !bytes.Equal(tx.Data(), tt.Data) {
+ return fmt.Errorf("Tx input data mismatch: got %x want %x", tx.Data(), tt.Data)
+ }
+ if tx.Gas().Cmp(tt.GasLimit) != 0 {
+ return fmt.Errorf("GasLimit mismatch: got %v, want %v", tx.Gas(), tt.GasLimit)
+ }
+ if tx.GasPrice().Cmp(tt.GasPrice) != 0 {
+ return fmt.Errorf("GasPrice mismatch: got %v, want %v", tx.GasPrice(), tt.GasPrice)
+ }
+ if tx.Nonce() != tt.Nonce {
+ return fmt.Errorf("Nonce mismatch: got %v, want %v", tx.Nonce(), tt.Nonce)
+ }
+ v, r, s := tx.RawSignatureValues()
+ if r.Cmp(tt.R) != 0 {
+ return fmt.Errorf("R mismatch: got %v, want %v", r, tt.R)
+ }
+ if s.Cmp(tt.S) != 0 {
+ return fmt.Errorf("S mismatch: got %v, want %v", s, tt.S)
+ }
+ if v.Cmp(tt.V) != 0 {
+ return fmt.Errorf("V mismatch: got %v, want %v", v, tt.V)
+ }
+ if tx.To() == nil {
+ if tt.To != (common.Address{}) {
+ return fmt.Errorf("To mismatch when recipient is nil (contract creation): %x", tt.To)
+ }
+ } else if *tx.To() != tt.To {
+ return fmt.Errorf("To mismatch: got %x, want %x", *tx.To(), tt.To)
+ }
+ if tx.Value().Cmp(tt.Value) != 0 {
+ return fmt.Errorf("Value mismatch: got %x, want %x", tx.Value(), tt.Value)
}
-
- expectedGasPrice := mustConvertBigInt(txTest.Transaction.GasPrice, 16)
- if expectedGasPrice.Cmp(decodedTx.GasPrice()) != 0 {
- return fmt.Errorf("GasPrice mismatch: %v %v", expectedGasPrice, decodedTx.GasPrice())
- }
-
- expectedNonce := mustConvertUint(txTest.Transaction.Nonce, 16)
- if expectedNonce != decodedTx.Nonce() {
- return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce())
- }
-
- v, r, s := decodedTx.RawSignatureValues()
- expectedR := mustConvertBigInt(txTest.Transaction.R, 16)
- if r.Cmp(expectedR) != 0 {
- return fmt.Errorf("R mismatch: %v %v", expectedR, r)
- }
- expectedS := mustConvertBigInt(txTest.Transaction.S, 16)
- if s.Cmp(expectedS) != 0 {
- return fmt.Errorf("S mismatch: %v %v", expectedS, s)
- }
- expectedV := mustConvertBigInt(txTest.Transaction.V, 16)
- if v.Cmp(expectedV) != 0 {
- return fmt.Errorf("V mismatch: %v %v", expectedV, v)
- }
-
- expectedTo := mustConvertAddress(txTest.Transaction.To)
- if decodedTx.To() == nil {
- if expectedTo != common.BytesToAddress([]byte{}) { // "empty" or "zero" address
- return fmt.Errorf("To mismatch when recipient is nil (contract creation): %v", expectedTo)
- }
- } else {
- if expectedTo != *decodedTx.To() {
- return fmt.Errorf("To mismatch: %v %v", expectedTo, *decodedTx.To())
- }
- }
-
- expectedValue := mustConvertBigInt(txTest.Transaction.Value, 16)
- if expectedValue.Cmp(decodedTx.Value()) != 0 {
- return fmt.Errorf("Value mismatch: %v %v", expectedValue, decodedTx.Value())
- }
-
return nil
}
diff --git a/tests/util.go b/tests/util.go
deleted file mode 100644
index ff02679ec4..0000000000
--- a/tests/util.go
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package tests
-
-import (
- "bytes"
- "fmt"
- "math/big"
- "os"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/math"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/params"
-)
-
-var (
- ForceJit bool
- EnableJit bool
-)
-
-func init() {
- log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
- if os.Getenv("JITVM") == "true" {
- ForceJit = true
- EnableJit = true
- }
-}
-
-func checkLogs(tlog []Log, logs []*types.Log) error {
- if len(tlog) != len(logs) {
- return fmt.Errorf("log length mismatch. Expected %d, got %d", len(tlog), len(logs))
- } else {
- for i, log := range tlog {
- if common.HexToAddress(log.AddressF) != logs[i].Address {
- return fmt.Errorf("log address expected %v got %x", log.AddressF, logs[i].Address)
- }
-
- if !bytes.Equal(logs[i].Data, common.FromHex(log.DataF)) {
- return fmt.Errorf("log data expected %v got %x", log.DataF, logs[i].Data)
- }
-
- if len(log.TopicsF) != len(logs[i].Topics) {
- return fmt.Errorf("log topics length expected %d got %d", len(log.TopicsF), logs[i].Topics)
- } else {
- for j, topic := range log.TopicsF {
- if common.HexToHash(topic) != logs[i].Topics[j] {
- return fmt.Errorf("log topic[%d] expected %v got %x", j, topic, logs[i].Topics[j])
- }
- }
- }
- genBloom := math.PaddedBigBytes(types.LogsBloom([]*types.Log{logs[i]}), 256)
-
- if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) {
- return fmt.Errorf("bloom mismatch")
- }
- }
- }
- return nil
-}
-
-type Account struct {
- Balance string
- Code string
- Nonce string
- Storage map[string]string
-}
-
-type Log struct {
- AddressF string `json:"address"`
- DataF string `json:"data"`
- TopicsF []string `json:"topics"`
- BloomF string `json:"bloom"`
-}
-
-func (self Log) Address() []byte { return common.Hex2Bytes(self.AddressF) }
-func (self Log) Data() []byte { return common.Hex2Bytes(self.DataF) }
-func (self Log) RlpData() interface{} { return nil }
-func (self Log) Topics() [][]byte {
- t := make([][]byte, len(self.TopicsF))
- for i, topic := range self.TopicsF {
- t[i] = common.Hex2Bytes(topic)
- }
- return t
-}
-
-func makePreState(db ethdb.Database, accounts map[string]Account) *state.StateDB {
- sdb := state.NewDatabase(db)
- statedb, _ := state.New(common.Hash{}, sdb)
- for addr, account := range accounts {
- insertAccount(statedb, addr, account)
- }
- // Commit and re-open to start with a clean state.
- root, _ := statedb.CommitTo(db, false)
- statedb, _ = state.New(root, sdb)
- return statedb
-}
-
-func insertAccount(state *state.StateDB, saddr string, account Account) {
- if common.IsHex(account.Code) {
- account.Code = account.Code[2:]
- }
- addr := common.HexToAddress(saddr)
- state.SetCode(addr, common.Hex2Bytes(account.Code))
- state.SetNonce(addr, math.MustParseUint64(account.Nonce))
- state.SetBalance(addr, math.MustParseBig256(account.Balance))
- for a, v := range account.Storage {
- state.SetState(addr, common.HexToHash(a), common.HexToHash(v))
- }
-}
-
-type VmEnv struct {
- CurrentCoinbase string
- CurrentDifficulty string
- CurrentGasLimit string
- CurrentNumber string
- CurrentTimestamp interface{}
- PreviousHash string
-}
-
-type VmTest struct {
- Callcreates interface{}
- //Env map[string]string
- Env VmEnv
- Exec map[string]string
- Transaction map[string]string
- Logs []Log
- Gas string
- Out string
- Post map[string]Account
- Pre map[string]Account
- PostStateRoot string
-}
-
-func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *state.StateDB, envValues map[string]string, tx map[string]string) (*vm.EVM, core.Message) {
- var (
- data = common.FromHex(tx["data"])
- gas = math.MustParseBig256(tx["gasLimit"])
- price = math.MustParseBig256(tx["gasPrice"])
- value = math.MustParseBig256(tx["value"])
- nonce = math.MustParseUint64(tx["nonce"])
- )
-
- origin := common.HexToAddress(tx["caller"])
- if len(tx["secretKey"]) > 0 {
- key, _ := crypto.HexToECDSA(tx["secretKey"])
- origin = crypto.PubkeyToAddress(key.PublicKey)
- }
-
- var to *common.Address
- if len(tx["to"]) > 2 {
- t := common.HexToAddress(tx["to"])
- to = &t
- }
-
- msg := types.NewMessage(origin, to, nonce, value, gas, price, data, true)
-
- initialCall := true
- canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool {
- if vmTest {
- if initialCall {
- initialCall = false
- return true
- }
- }
- return core.CanTransfer(db, address, amount)
- }
- transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
- if vmTest {
- return
- }
- core.Transfer(db, sender, recipient, amount)
- }
-
- context := vm.Context{
- CanTransfer: canTransfer,
- Transfer: transfer,
- GetHash: func(n uint64) common.Hash {
- return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
- },
-
- Origin: origin,
- Coinbase: common.HexToAddress(envValues["currentCoinbase"]),
- BlockNumber: math.MustParseBig256(envValues["currentNumber"]),
- Time: math.MustParseBig256(envValues["currentTimestamp"]),
- GasLimit: math.MustParseBig256(envValues["currentGasLimit"]),
- Difficulty: math.MustParseBig256(envValues["currentDifficulty"]),
- GasPrice: price,
- }
- if context.GasPrice == nil {
- context.GasPrice = new(big.Int)
- }
- return vm.NewEVM(context, statedb, chainConfig, vm.Config{NoRecursion: vmTest}), msg
-}
diff --git a/tests/vm_test.go b/tests/vm_test.go
index b546007fb9..5289ba3559 100644
--- a/tests/vm_test.go
+++ b/tests/vm_test.go
@@ -17,122 +17,21 @@
package tests
import (
- "os"
- "path/filepath"
"testing"
+
+ "github.com/ethereum/go-ethereum/core/vm"
)
-func BenchmarkVmAckermann32Tests(b *testing.B) {
- fn := filepath.Join(vmTestDir, "vmPerformanceTest.json")
- if err := BenchVmTest(fn, bconf{"ackermann32", os.Getenv("JITFORCE") == "true", os.Getenv("JITVM") == "true"}, b); err != nil {
- b.Error(err)
- }
-}
+func TestVM(t *testing.T) {
+ t.Parallel()
+ vmt := new(testMatcher)
+ vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution")
+ vmt.skipShortMode("^vmPerformanceTest.json")
+ vmt.skipShortMode("^vmInputLimits(Light)?.json")
-func BenchmarkVmFibonacci16Tests(b *testing.B) {
- fn := filepath.Join(vmTestDir, "vmPerformanceTest.json")
- if err := BenchVmTest(fn, bconf{"fibonacci16", os.Getenv("JITFORCE") == "true", os.Getenv("JITVM") == "true"}, b); err != nil {
- b.Error(err)
- }
-}
-
-// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
-func TestVmVMArithmetic(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmArithmeticTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmBitwiseLogicOperation(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmBitwiseLogicOperationTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmBlockInfo(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmBlockInfoTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmEnvironmentalInfo(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmEnvironmentalInfoTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmFlowOperation(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmIOandFlowOperationsTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmLogTest(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmLogTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmPerformance(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmPerformanceTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmPushDupSwap(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmPushDupSwapTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmVMSha3(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmSha3Test.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVm(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmtests.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmLog(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmLogTest.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmInputLimits(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmInputLimits.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmInputLimitsLight(t *testing.T) {
- fn := filepath.Join(vmTestDir, "vmInputLimitsLight.json")
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
-}
-
-func TestVmVMRandom(t *testing.T) {
- fns, _ := filepath.Glob(filepath.Join(baseDir, "RandomTests", "*"))
- for _, fn := range fns {
- if err := RunVmTest(fn, VmSkipTests); err != nil {
- t.Error(err)
- }
- }
+ vmt.walk(t, vmTestDir, func(t *testing.T, name string, test *VMTest) {
+ withTrace(t, test.json.Exec.GasLimit, func(vmconfig vm.Config) error {
+ return vmt.checkFailure(t, name, test.Run(vmconfig))
+ })
+ })
}
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index e7fe74f49b..afdd896c35 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -18,218 +18,132 @@ package tests
import (
"bytes"
+ "encoding/json"
"fmt"
- "io"
"math/big"
- "strconv"
- "testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
-func RunVmTestWithReader(r io.Reader, skipTests []string) error {
- tests := make(map[string]VmTest)
- err := readJson(r, &tests)
- if err != nil {
- return err
- }
-
- if err != nil {
- return err
- }
-
- if err := runVmTests(tests, skipTests); err != nil {
- return err
- }
-
- return nil
+// VMTest checks EVM execution without block or transaction context.
+// See https://github.com/ethereum/tests/wiki/VM-Tests for the test format specification.
+type VMTest struct {
+ json vmJSON
}
-type bconf struct {
- name string
- precomp bool
- jit bool
+func (t *VMTest) UnmarshalJSON(data []byte) error {
+ return json.Unmarshal(data, &t.json)
}
-func BenchVmTest(p string, conf bconf, b *testing.B) error {
- tests := make(map[string]VmTest)
- err := readJsonFile(p, &tests)
- if err != nil {
- return err
- }
-
- test, ok := tests[conf.name]
- if !ok {
- return fmt.Errorf("test not found: %s", conf.name)
- }
-
- env := make(map[string]string)
- env["currentCoinbase"] = test.Env.CurrentCoinbase
- env["currentDifficulty"] = test.Env.CurrentDifficulty
- env["currentGasLimit"] = test.Env.CurrentGasLimit
- env["currentNumber"] = test.Env.CurrentNumber
- env["previousHash"] = test.Env.PreviousHash
- if n, ok := test.Env.CurrentTimestamp.(float64); ok {
- env["currentTimestamp"] = strconv.Itoa(int(n))
- } else {
- env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
- }
-
- /*
- if conf.precomp {
- program := vm.NewProgram(test.code)
- err := vm.AttachProgram(program)
- if err != nil {
- return err
- }
- }
- */
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- benchVmTest(test, env, b)
- }
-
- return nil
+type vmJSON struct {
+ Env stEnv `json:"env"`
+ Exec vmExec `json:"exec"`
+ Logs []stLog `json:"logs"`
+ GasRemaining *math.HexOrDecimal64 `json:"gas"`
+ Out hexutil.Bytes `json:"out"`
+ Pre core.GenesisAlloc `json:"pre"`
+ Post core.GenesisAlloc `json:"post"`
+ PostStateRoot common.Hash `json:"postStateRoot"`
}
-func benchVmTest(test VmTest, env map[string]string, b *testing.B) {
- b.StopTimer()
+//go:generate gencodec -type vmExec -field-override vmExecMarshaling -out gen_vmexec.go
+
+type vmExec struct {
+ Address common.Address `json:"address" gencodec:"required"`
+ Caller common.Address `json:"caller" gencodec:"required"`
+ Origin common.Address `json:"origin" gencodec:"required"`
+ Code []byte `json:"code" gencodec:"required"`
+ Data []byte `json:"data" gencodec:"required"`
+ Value *big.Int `json:"value" gencodec:"required"`
+ GasLimit uint64 `json:"gas" gencodec:"required"`
+ GasPrice *big.Int `json:"gasPrice" gencodec:"required"`
+}
+
+type vmExecMarshaling struct {
+ Address common.UnprefixedAddress
+ Caller common.UnprefixedAddress
+ Origin common.UnprefixedAddress
+ Code hexutil.Bytes
+ Data hexutil.Bytes
+ Value *math.HexOrDecimal256
+ GasLimit math.HexOrDecimal64
+ GasPrice *math.HexOrDecimal256
+}
+
+func (t *VMTest) Run(vmconfig vm.Config) error {
db, _ := ethdb.NewMemDatabase()
- statedb := makePreState(db, test.Pre)
- b.StartTimer()
+ statedb := makePreState(db, t.json.Pre)
+ ret, gasRemaining, err := t.exec(statedb, vmconfig)
- RunVm(statedb, env, test.Exec)
-}
-
-func RunVmTest(p string, skipTests []string) error {
- tests := make(map[string]VmTest)
- err := readJsonFile(p, &tests)
- if err != nil {
- return err
- }
-
- if err := runVmTests(tests, skipTests); err != nil {
- return err
- }
-
- return nil
-}
-
-func runVmTests(tests map[string]VmTest, skipTests []string) error {
- skipTest := make(map[string]bool, len(skipTests))
- for _, name := range skipTests {
- skipTest[name] = true
- }
-
- for name, test := range tests {
- if skipTest[name] /*|| name != "exp0"*/ {
- log.Info(fmt.Sprint("Skipping VM test", name))
- continue
+ if t.json.GasRemaining == nil {
+ if err == nil {
+ return fmt.Errorf("gas unspecified (indicating an error), but VM returned no error")
}
-
- if err := runVmTest(test); err != nil {
- return fmt.Errorf("%s %s", name, err.Error())
+ if gasRemaining > 0 {
+ return fmt.Errorf("gas unspecified (indicating an error), but VM returned gas remaining > 0")
}
-
- log.Info(fmt.Sprint("VM test passed: ", name))
- //fmt.Println(string(statedb.Dump()))
+ return nil
}
- return nil
-}
-
-func runVmTest(test VmTest) error {
- db, _ := ethdb.NewMemDatabase()
- statedb := makePreState(db, test.Pre)
-
- // XXX Yeah, yeah...
- env := make(map[string]string)
- env["currentCoinbase"] = test.Env.CurrentCoinbase
- env["currentDifficulty"] = test.Env.CurrentDifficulty
- env["currentGasLimit"] = test.Env.CurrentGasLimit
- env["currentNumber"] = test.Env.CurrentNumber
- env["previousHash"] = test.Env.PreviousHash
- if n, ok := test.Env.CurrentTimestamp.(float64); ok {
- env["currentTimestamp"] = strconv.Itoa(int(n))
- } else {
- env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
+ // Test declares gas, expecting outputs to match.
+ if !bytes.Equal(ret, t.json.Out) {
+ return fmt.Errorf("return data mismatch: got %x, want %x", ret, t.json.Out)
}
-
- var (
- ret []byte
- gas *big.Int
- err error
- logs []*types.Log
- )
-
- ret, logs, gas, err = RunVm(statedb, env, test.Exec)
-
- // Compare expected and actual return
- rexp := common.FromHex(test.Out)
- if !bytes.Equal(rexp, ret) {
- return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
+ if gasRemaining != uint64(*t.json.GasRemaining) {
+ return fmt.Errorf("remaining gas %v, want %v", gasRemaining, *t.json.GasRemaining)
}
-
- // Check gas usage
- if len(test.Gas) == 0 && err == nil {
- return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful")
- } else {
- gexp := math.MustParseBig256(test.Gas)
- if gexp.Cmp(gas) != 0 {
- return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas)
- }
- }
-
- // check post state
- for address, account := range test.Post {
- accountAddr := common.HexToAddress(address)
- if !statedb.Exist(accountAddr) {
- continue
- }
- for addr, value := range account.Storage {
- v := statedb.GetState(accountAddr, common.HexToHash(addr))
- vexp := common.HexToHash(value)
- if v != vexp {
- return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", addr[:4], addr, vexp, v, vexp.Big(), v.Big())
+ for addr, account := range t.json.Post {
+ for k, wantV := range account.Storage {
+ if haveV := statedb.GetState(addr, k); haveV != wantV {
+ return fmt.Errorf("wrong storage value at %x:\n got %x\n want %x", k, haveV, wantV)
}
}
}
+ // if root := statedb.IntermediateRoot(false); root != t.json.PostStateRoot {
+ // return fmt.Errorf("post state root mismatch, got %x, want %x", root, t.json.PostStateRoot)
+ // }
+ return checkLogs(statedb.Logs(), t.json.Logs)
+}
- // check logs
- if len(test.Logs) > 0 {
- lerr := checkLogs(test.Logs, logs)
- if lerr != nil {
- return lerr
+func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) {
+ evm := t.newEVM(statedb, vmconfig)
+ e := t.json.Exec
+ return evm.Call(vm.AccountRef(e.Caller), e.Address, e.Data, e.GasLimit, e.Value)
+}
+
+func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {
+ initialCall := true
+ canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool {
+ if initialCall {
+ initialCall = false
+ return true
}
+ return core.CanTransfer(db, address, amount)
}
-
- return nil
+ transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {}
+ context := vm.Context{
+ CanTransfer: canTransfer,
+ Transfer: transfer,
+ GetHash: vmTestBlockHash,
+ Origin: t.json.Exec.Origin,
+ Coinbase: t.json.Env.Coinbase,
+ BlockNumber: new(big.Int).SetUint64(t.json.Env.Number),
+ Time: new(big.Int).SetUint64(t.json.Env.Timestamp),
+ GasLimit: t.json.Env.GasLimit,
+ Difficulty: t.json.Env.Difficulty,
+ GasPrice: t.json.Exec.GasPrice,
+ }
+ vmconfig.NoRecursion = true
+ return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig)
}
-func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*types.Log, *big.Int, error) {
- chainConfig := ¶ms.ChainConfig{
- HomesteadBlock: params.MainnetChainConfig.HomesteadBlock,
- DAOForkBlock: params.MainnetChainConfig.DAOForkBlock,
- DAOForkSupport: true,
- }
- var (
- to = common.HexToAddress(exec["address"])
- from = common.HexToAddress(exec["caller"])
- data = common.FromHex(exec["data"])
- gas = math.MustParseBig256(exec["gas"])
- value = math.MustParseBig256(exec["value"])
- )
- caller := statedb.GetOrNewStateObject(from)
- vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
-
- environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
- ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value)
- return ret, statedb.Logs(), new(big.Int).SetUint64(g), err
+func vmTestBlockHash(n uint64) common.Hash {
+ return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
}