github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/config_test.go (about)

     1  package core
     2  
     3  import (
     4  	"io"
     5  	"math/big"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"path/filepath"
    11  
    12  	"github.com/ethereumproject/go-ethereum/common"
    13  	"github.com/ethereumproject/go-ethereum/core/types"
    14  	"github.com/ethereumproject/go-ethereum/ethdb"
    15  	"reflect"
    16  )
    17  
    18  func TestConfigErrorProperties(t *testing.T) {
    19  	if IsValidateError(ErrHashKnownBad) {
    20  		t.Error("ErrHashKnownBad is a validation error")
    21  	}
    22  	if !IsValidateError(ErrHashKnownFork) {
    23  		t.Error("ErrHashKnownFork is not a validation error")
    24  	}
    25  }
    26  
    27  func TestChainConfig_IsHomestead(t *testing.T) {
    28  	config := DefaultConfigMainnet.ChainConfig
    29  
    30  	if config.IsHomestead(big.NewInt(10000)) {
    31  		t.Errorf("Unexpected for %d", 10000)
    32  	}
    33  
    34  	if !config.IsHomestead(big.NewInt(1920000)) {
    35  		t.Errorf("Expected for %d", 1920000)
    36  	}
    37  	if !config.IsHomestead(big.NewInt(2325166)) {
    38  		t.Errorf("Expected for %d", 2325166)
    39  	}
    40  	if !config.IsHomestead(big.NewInt(3000000)) {
    41  		t.Errorf("Expected for %d", 3000000)
    42  	}
    43  	if !config.IsHomestead(big.NewInt(3000001)) {
    44  		t.Errorf("Expected for %d", 3000001)
    45  	}
    46  	if !config.IsHomestead(big.NewInt(4000000)) {
    47  		t.Errorf("Expected for %d", 3000000)
    48  	}
    49  	if !config.IsHomestead(big.NewInt(5000000)) {
    50  		t.Errorf("Expected for %d", 5000000)
    51  	}
    52  	if !config.IsHomestead(big.NewInt(5000001)) {
    53  		t.Errorf("Expected for %d", 5000001)
    54  	}
    55  }
    56  
    57  func TestChainConfig_IsDiehard(t *testing.T) {
    58  	config := DefaultConfigMainnet.ChainConfig
    59  
    60  	if config.IsDiehard(big.NewInt(1920000)) {
    61  		t.Errorf("Unexpected for %d", 1920000)
    62  	}
    63  
    64  	if config.IsDiehard(big.NewInt(2325166)) {
    65  		t.Errorf("Unexpected for %d", 2325166)
    66  	}
    67  
    68  	if !config.IsDiehard(big.NewInt(3000000)) {
    69  		t.Errorf("Expected for %d", 3000000)
    70  	}
    71  	if !config.IsDiehard(big.NewInt(3000001)) {
    72  		t.Errorf("Expected for %d", 3000001)
    73  	}
    74  	if !config.IsDiehard(big.NewInt(4000000)) {
    75  		t.Errorf("Expected for %d", 3000000)
    76  	}
    77  
    78  	if !config.IsDiehard(big.NewInt(5000000)) {
    79  		t.Errorf("Expected for %d", 5000000)
    80  	}
    81  	if !config.IsDiehard(big.NewInt(5000001)) {
    82  		t.Errorf("Expected for %d", 5000001)
    83  	}
    84  }
    85  
    86  func TestChainConfig_IsExplosion(t *testing.T) {
    87  	config := DefaultConfigMainnet.ChainConfig
    88  
    89  	if config.IsExplosion(big.NewInt(1920000)) {
    90  		t.Errorf("Unexpected for %d", 1920000)
    91  	}
    92  
    93  	if config.IsExplosion(big.NewInt(2325166)) {
    94  		t.Errorf("Unexpected for %d", 2325166)
    95  	}
    96  
    97  	// Default Diehard block is 3000000
    98  	if config.IsExplosion(big.NewInt(3000000)) {
    99  		t.Errorf("Unxpected for %d", 3000000)
   100  	}
   101  	if config.IsExplosion(big.NewInt(3000001)) {
   102  		t.Errorf("Unxpected for %d", 3000001)
   103  	}
   104  	if config.IsExplosion(big.NewInt(4000000)) {
   105  		t.Errorf("Unxpected for %d", 3000000)
   106  	}
   107  
   108  	// Default BombDelay length is 2000000.
   109  	if !config.IsExplosion(big.NewInt(5000000)) {
   110  		t.Errorf("Expected for %d", 5000000)
   111  	}
   112  	if !config.IsExplosion(big.NewInt(5000001)) {
   113  		t.Errorf("Expected for %d", 5000001)
   114  	}
   115  
   116  }
   117  
   118  func sameGenesisDumpAllocationsBalances(gd1, gd2 *GenesisDump) bool {
   119  	for address, alloc := range gd2.Alloc {
   120  		if gd1.Alloc[address] != nil {
   121  			bal1, _ := new(big.Int).SetString(gd1.Alloc[address].Balance, 0)
   122  			bal2, _ := new(big.Int).SetString(alloc.Balance, 0)
   123  			if bal1.Cmp(bal2) != 0 {
   124  				return false
   125  			}
   126  		} else if alloc.Balance != "" {
   127  			return false
   128  		}
   129  
   130  	}
   131  	return true
   132  }
   133  
   134  // TestMakeGenesisDump is a unit-ish test for MakeGenesisDump()
   135  func TestMakeGenesisDump(t *testing.T) {
   136  	// setup so we have a genesis block in this test db
   137  	db, _ := ethdb.NewMemDatabase()
   138  	genesisDump := &GenesisDump{
   139  		Nonce:      "0x0000000000000042",
   140  		Timestamp:  "0x0000000000000000000000000000000000000000000000000000000000000000",
   141  		Coinbase:   "0x0000000000000000000000000000000000000000",
   142  		Difficulty: "0x0000000000000000000000000000000000000000000000000000000400000000",
   143  		ExtraData:  "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
   144  		GasLimit:   "0x0000000000000000000000000000000000000000000000000000000000001388",
   145  		Mixhash:    "0x0000000000000000000000000000000000000000000000000000000000000000",
   146  		ParentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
   147  		Alloc: map[hex]*GenesisDumpAlloc{
   148  			"000d836201318ec6899a67540690382780743280": {Balance: "200000000000000000000"},
   149  			"001762430ea9c3a26e5749afdb70da5f78ddbb8c": {Balance: "200000000000000000000"},
   150  			"001d14804b399c6ef80e64576f657660804fec0b": {Balance: "4200000000000000000000"},
   151  			"0032403587947b9f15622a68d104d54d33dbd1cd": {Balance: "77500000000000000000"},
   152  			"00497e92cdc0e0b963d752b2296acb87da828b24": {Balance: "194800000000000000000"},
   153  			"004bfbe1546bc6c65b5c7eaa55304b38bbfec6d3": {Balance: "2000000000000000000000"},
   154  			"005a9c03f69d17d66cbb8ad721008a9ebbb836fb": {Balance: "2000000000000000000000"},
   155  		},
   156  	}
   157  	gBlock1, err := WriteGenesisBlock(db, genesisDump)
   158  	if err != nil {
   159  		t.Errorf("WriteGenesisBlock could not setup genesisDump: err: %v", err)
   160  	}
   161  
   162  	// ensure equivalent genesis dumps in and out
   163  	gotGenesisDump, err := MakeGenesisDump(db)
   164  	if gotGenesisDump.Nonce != genesisDump.Nonce {
   165  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump nonce: wanted: %v, got: %v", genesisDump.Nonce, gotGenesisDump.Nonce)
   166  	}
   167  	if gotGenesisDump.Timestamp != genesisDump.Timestamp {
   168  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump timestamp: wanted: %v, got: %v", genesisDump.Timestamp, gotGenesisDump.Timestamp)
   169  	}
   170  	if gotGenesisDump.Coinbase != genesisDump.Coinbase {
   171  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump coinbase: wanted: %v, got: %v", genesisDump.Coinbase, gotGenesisDump.Coinbase)
   172  	}
   173  	if gotGenesisDump.Difficulty != genesisDump.Difficulty {
   174  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump difficulty: wanted: %v, got: %v", genesisDump.Difficulty, gotGenesisDump.Difficulty)
   175  	}
   176  	if gotGenesisDump.ExtraData != genesisDump.ExtraData {
   177  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump extra data: wanted: %v, got: %v", genesisDump.ExtraData, gotGenesisDump.ExtraData)
   178  	}
   179  	if gotGenesisDump.GasLimit != genesisDump.GasLimit {
   180  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump gaslimit: wanted: %v, got: %v", genesisDump.GasLimit, gotGenesisDump.GasLimit)
   181  	}
   182  	if gotGenesisDump.Mixhash != genesisDump.Mixhash {
   183  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump mixhash: wanted: %v, got: %v", genesisDump.Mixhash, gotGenesisDump.Mixhash)
   184  	}
   185  	if gotGenesisDump.ParentHash != genesisDump.ParentHash {
   186  		t.Errorf("MakeGenesisDump failed to make equivalent genesis dump parenthash: wanted: %v, got: %v", genesisDump.ParentHash, gotGenesisDump.ParentHash)
   187  	}
   188  	if !sameGenesisDumpAllocationsBalances(genesisDump, gotGenesisDump) {
   189  		t.Error("MakeGenesisDump failed to make equivalent genesis dump allocations.")
   190  	}
   191  
   192  	// ensure equivalent genesis blocks in and out
   193  	gBlock2, err := WriteGenesisBlock(db, gotGenesisDump)
   194  	if err != nil {
   195  		t.Errorf("WriteGenesisBlock could not setup gotGenesisDump: err: %v", err)
   196  	}
   197  
   198  	if gBlock1.Hash() != gBlock2.Hash() {
   199  		t.Errorf("MakeGenesisDump failed to make genesis block with equivalent hashes: wanted: %v, got: %v", gBlock1.Hash(), gBlock2.Hash())
   200  	}
   201  	db.Close()
   202  }
   203  
   204  func TestMakeGenesisDump2(t *testing.T) {
   205  	// setup so we have a genesis block in this test db
   206  	for i, gen := range []*GenesisDump{DefaultConfigMainnet.Genesis, DefaultConfigMorden.Genesis} {
   207  		db, _ := ethdb.NewMemDatabase()
   208  		genesisDump := gen
   209  		gBlock1, err := WriteGenesisBlock(db, genesisDump)
   210  		if err != nil {
   211  			t.Errorf("WriteGenesisBlock could not setup initial genesisDump: %v, err: %v", i, err)
   212  		}
   213  
   214  		// ensure equivalent genesis dumps in and out
   215  		gotGenesisDump, err := MakeGenesisDump(db)
   216  
   217  		// ensure equivalent genesis blocks in and out
   218  		gBlock2, err := WriteGenesisBlock(db, gotGenesisDump)
   219  		if err != nil {
   220  			t.Errorf("WriteGenesisBlock could not setup gotGenesisDump: %v, err: %v", i, err)
   221  		}
   222  
   223  		if !sameGenesisDumpAllocationsBalances(genesisDump, gotGenesisDump) {
   224  			t.Error("MakeGenesisDump failed to make equivalent genesis dump allocations.")
   225  		}
   226  
   227  		if gBlock1.Hash() != gBlock2.Hash() {
   228  			t.Errorf(`MakeGenesisDump failed to make genesis block with equivalent hashes: %v: wanted: %v, got: %v
   229  			WANTED:
   230  			%v
   231  
   232  			GOT:
   233  			%v`, i, gBlock1.Hash().Hex(), gBlock2.Hash().Hex(), gBlock1.String(), gBlock2.String())
   234  
   235  		}
   236  		db.Close()
   237  	}
   238  }
   239  
   240  func getDefaultChainConfigSorted() *ChainConfig {
   241  	return DefaultConfigMainnet.ChainConfig.SortForks()
   242  }
   243  
   244  // Unit-y tests.
   245  
   246  func TestChainConfig_HasFeature(t *testing.T) {
   247  	c := DefaultConfigMorden.ChainConfig.SortForks()
   248  	for _, id := range allAvailableTestnetConfigKeys {
   249  		if _, _, ok := c.HasFeature(id); !ok {
   250  			t.Errorf("feature not found: %v", id)
   251  		}
   252  	}
   253  	c = getDefaultChainConfigSorted()
   254  	for _, id := range allAvailableDefaultConfigKeys {
   255  		if _, _, ok := c.HasFeature(id); !ok {
   256  			t.Errorf("feature not found: %v", id)
   257  		}
   258  	}
   259  
   260  	// never gets unavailable keys
   261  	c = DefaultConfigMorden.ChainConfig.SortForks()
   262  	for _, id := range unavailableConfigKeys {
   263  		if _, _, ok := c.HasFeature(id); ok {
   264  			t.Errorf("nonexisting feature found: %v", id)
   265  		}
   266  	}
   267  	c = getDefaultChainConfigSorted()
   268  	for _, id := range unavailableConfigKeys {
   269  		if _, _, ok := c.HasFeature(id); ok {
   270  			t.Errorf("nonexisting feature found: %v", id)
   271  		}
   272  	}
   273  }
   274  
   275  // TestChainConfig_GetFeature should be able to get all features described in DefaultChainConfigMainnet.
   276  func TestChainConfig_GetFeature(t *testing.T) {
   277  	c := getDefaultChainConfigSorted()
   278  	var dict = make(map[*big.Int][]string)
   279  	for _, fork := range c.Forks {
   280  		for _, feat := range fork.Features {
   281  			dict[fork.Block] = append(dict[fork.Block], feat.ID)
   282  		}
   283  	}
   284  	for block, ids := range dict {
   285  		for _, name := range ids {
   286  			feat, fork, ok := c.GetFeature(block, name)
   287  			if !ok {
   288  				t.Errorf("expected feature exist: feat: %v, fork: %v, block: %v", feat, fork, block)
   289  			}
   290  		}
   291  	}
   292  }
   293  
   294  var allAvailableDefaultConfigKeys = []string{
   295  	"difficulty",
   296  	"gastable",
   297  	"eip155",
   298  }
   299  var allAvailableTestnetConfigKeys = []string{
   300  	"difficulty",
   301  	"gastable",
   302  	"eip155",
   303  	"reward",
   304  }
   305  var unavailableConfigKeys = []string{
   306  	"foo",
   307  	"bar",
   308  	"monkey",
   309  }
   310  
   311  // veryHighBlock is a block in the far distant future (so far, in fact, that it will never actually exist)
   312  // Used to test cumulative aggregation functions, ie "eventually".
   313  var veryHighBlock *big.Int = big.NewInt(250000000)
   314  
   315  // TestChainConfig_EventuallyGetAllPossibleFeatures should aggregate all available features from previous branches
   316  func TestChainConfig_GetFeature2_EventuallyGetAllPossibleFeatures(t *testing.T) {
   317  	c := getDefaultChainConfigSorted()
   318  	for _, id := range allAvailableDefaultConfigKeys {
   319  		if _, _, ok := c.GetFeature(veryHighBlock, id); !ok {
   320  			t.Errorf("could not get feature with id: %v, at block: %v", id, big.NewInt(5000000))
   321  		}
   322  	}
   323  }
   324  
   325  // TestChainConfig_NeverGetNonexistantFeatures should never eventually collect features that don't exist
   326  func TestChainConfig_GetFeature3_NeverGetNonexistantFeatures(t *testing.T) {
   327  	c := getDefaultChainConfigSorted()
   328  	for _, id := range unavailableConfigKeys {
   329  		if feat, _, ok := c.GetFeature(veryHighBlock, id); ok {
   330  			t.Errorf("found unexpected feature: %v, for name: %v, at block: %v", feat, id, big.NewInt(5000000))
   331  		}
   332  	}
   333  }
   334  
   335  func TestChainConfig_GetFeature4_WorkForHighNumbers(t *testing.T) {
   336  	c := getDefaultChainConfigSorted()
   337  	ultraHighBlock := big.NewInt(99999999999999999)
   338  	if _, _, ok := c.GetFeature(ultraHighBlock, "difficulty"); !ok {
   339  		t.Errorf("unexpected unfound difficulty feature for far-future block: %v", ultraHighBlock)
   340  	}
   341  }
   342  
   343  func TestChainConfig_GetChainID(t *testing.T) {
   344  	// Test default hardcoded configs.
   345  	if DefaultConfigMainnet.ChainConfig.GetChainID().Cmp(DefaultConfigMainnet.ChainConfig.GetChainID()) != 0 {
   346  		t.Errorf("got: %v, want: %v", DefaultConfigMainnet.ChainConfig.GetChainID(), DefaultConfigMainnet.ChainConfig.GetChainID())
   347  	}
   348  	if DefaultConfigMorden.ChainConfig.GetChainID().Cmp(DefaultConfigMorden.ChainConfig.GetChainID()) != 0 {
   349  		t.Errorf("got: %v, want: %v", DefaultConfigMorden.ChainConfig.GetChainID(), DefaultConfigMorden.ChainConfig.GetChainID())
   350  	}
   351  
   352  	// If no chainID (config is empty) returns 0.
   353  	c := &ChainConfig{}
   354  	cid := c.GetChainID()
   355  	// check is zero
   356  	if cid.Cmp(new(big.Int)) != 0 {
   357  		t.Errorf("got: %v, want: %v", cid, new(big.Int))
   358  	}
   359  
   360  	// Test parsing default external mainnet config.
   361  	cases := map[string]*big.Int{
   362  		"../core/config/mainnet.json": DefaultConfigMainnet.ChainConfig.GetChainID(),
   363  		"../core/config/morden.json":  DefaultConfigMorden.ChainConfig.GetChainID(),
   364  	}
   365  	for extConfigPath, wantInt := range cases {
   366  		p, e := filepath.Abs(extConfigPath)
   367  		if e != nil {
   368  			t.Fatalf("filepath err: %v", e)
   369  		}
   370  		extConfig, err := ReadExternalChainConfigFromFile(p)
   371  		if err != nil {
   372  			t.Fatalf("could not decode file: %v", err)
   373  		}
   374  		if extConfig.ChainConfig.GetChainID().Cmp(wantInt) != 0 {
   375  			t.Errorf("got: %v, want: %v", extConfig.ChainConfig.GetChainID(), wantInt)
   376  		}
   377  	}
   378  }
   379  
   380  // Acceptance-y tests.
   381  
   382  // Test GetFeature gets expected feature values from default configuration data...
   383  
   384  // TestChainConfig_GetFeature_DefaultEIP155 should get the eip155 feature for (only and above) its default implemented block.
   385  func TestChainConfig_GetFeature5_DefaultEIP155(t *testing.T) {
   386  	c := getDefaultChainConfigSorted()
   387  	var tables = map[*big.Int]*big.Int{
   388  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block, big.NewInt(1)): nil,
   389  		DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block:                                   nil,
   390  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block, big.NewInt(1)): nil,
   391  
   392  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block, big.NewInt(1)): nil,
   393  		DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block:                                   nil,
   394  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block, big.NewInt(1)): nil,
   395  
   396  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block, big.NewInt(1)): nil,
   397  		DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block:                                   big.NewInt(61),
   398  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block, big.NewInt(1)): big.NewInt(61),
   399  	}
   400  	for block, expected := range tables {
   401  		feat, fork, ok := c.GetFeature(block, "eip155")
   402  		if expected != nil {
   403  			if !ok {
   404  				t.Errorf("Expected eip155 feature to exist. feat: %v, fork: %v, block: %v", feat, fork, block)
   405  			}
   406  			val, ok := feat.GetBigInt("chainID")
   407  			if !ok {
   408  				t.Errorf("failed to get value for eip155 feature. feat: %v, fork: %v, block: %v", feat, fork, block)
   409  			}
   410  			if val.Cmp(expected) != 0 {
   411  				t.Errorf("want: %v, got: %v", expected, val)
   412  			}
   413  		} else {
   414  			if ok {
   415  				t.Errorf("Unexpected eip155 feature exists. feat: %v, fork: %v, block: %v", feat, fork, block)
   416  			}
   417  		}
   418  	}
   419  }
   420  
   421  // TestChainConfig_GetFeature_DefaultGasTables sets that GetFeatures gets expected feature values for default fork configs.
   422  func TestChainConfig_GetFeature6_DefaultGasTables(t *testing.T) {
   423  	c := getDefaultChainConfigSorted()
   424  	var tables = map[*big.Int]string{
   425  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block, big.NewInt(1)): "",
   426  		DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block:                                   "homestead",
   427  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block, big.NewInt(1)): "homestead",
   428  
   429  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block, big.NewInt(1)): "homestead",
   430  		DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block:                                   "eip150",
   431  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block, big.NewInt(1)): "eip150",
   432  
   433  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block, big.NewInt(1)): "eip150",
   434  		DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block:                                   "eip160",
   435  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block, big.NewInt(1)): "eip160",
   436  	}
   437  	for block, expected := range tables {
   438  		feat, fork, ok := c.GetFeature(block, "gastable")
   439  		if expected != "" {
   440  			if !ok {
   441  				t.Errorf("Expected gastable feature to exist. feat: %v, fork: %v, block: %v", feat, fork, block)
   442  			}
   443  			val, ok := feat.GetString("type")
   444  			if !ok {
   445  				t.Errorf("failed to get value for gastable feature. feat: %v, fork: %v, block: %v", feat, fork, block)
   446  			}
   447  			if val != expected {
   448  				t.Errorf("want: %v, got: %v", expected, val)
   449  			}
   450  		} else {
   451  			if ok {
   452  				t.Errorf("Unexpected gastable feature exists. feat: %v, fork: %v, block: %v", feat, fork, block)
   453  			}
   454  		}
   455  	}
   456  }
   457  
   458  // TestChainConfig_GetFeature_DefaultGasTables sets that GetFeatures gets expected feature values for default fork configs.
   459  func TestChainConfig_GetFeature7_DefaultDifficulty(t *testing.T) {
   460  	c := getDefaultChainConfigSorted()
   461  	var tables = map[*big.Int]string{
   462  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block, big.NewInt(1)): "",
   463  		DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block:                                   "homestead",
   464  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("Homestead").Block, big.NewInt(1)): "homestead",
   465  
   466  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block, big.NewInt(1)): "homestead",
   467  		DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block:                                   "homestead",
   468  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("GasReprice").Block, big.NewInt(1)): "homestead",
   469  
   470  		big.NewInt(0).Sub(DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block, big.NewInt(1)): "homestead",
   471  		DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block:                                   "ecip1010",
   472  		big.NewInt(0).Add(DefaultConfigMainnet.ChainConfig.ForkByName("Diehard").Block, big.NewInt(1)): "ecip1010",
   473  	}
   474  	for block, expected := range tables {
   475  		feat, fork, ok := c.GetFeature(block, "difficulty")
   476  		if expected != "" {
   477  			if !ok {
   478  				t.Errorf("Expected difficulty feature to exist. feat: %v, fork: %v, block: %v", feat, fork, block)
   479  			}
   480  			val, ok := feat.GetString("type")
   481  			if !ok {
   482  				t.Errorf("failed to get value for difficulty feature. feat: %v, fork: %v, block: %v", feat, fork, block)
   483  			}
   484  			if val != expected {
   485  				t.Errorf("want: %v, got: %v", expected, val)
   486  			}
   487  		} else {
   488  			if ok {
   489  				t.Errorf("Unexpected difficulty feature exists. feat: %v, fork: %v, block: %v", feat, fork, block)
   490  			}
   491  		}
   492  	}
   493  }
   494  
   495  func TestChainConfig_SortForks(t *testing.T) {
   496  	// check code data default
   497  	c := getDefaultChainConfigSorted()
   498  	n := big.NewInt(0)
   499  	for _, fork := range c.Forks {
   500  		if n.Cmp(fork.Block) > 0 {
   501  			t.Errorf("unexpected fork block: %v is greater than: %v", fork.Block, n)
   502  		}
   503  		n = fork.Block
   504  	}
   505  
   506  	// introduce disorder
   507  	f := &Fork{}
   508  	f.Block = big.NewInt(0).Sub(c.Forks[0].Block, big.NewInt(1))
   509  	c.Forks = append(c.Forks, f) // last fork should be out of order
   510  
   511  	c.SortForks()
   512  	n = big.NewInt(0)
   513  	for _, fork := range c.Forks {
   514  		if n.Cmp(fork.Block) > 0 {
   515  			t.Errorf("unexpected fork block: %v is greater than: %v", fork.Block, n)
   516  		}
   517  		n = fork.Block
   518  	}
   519  }
   520  
   521  func TestChainConfigGetSet(t *testing.T) {
   522  	c := getDefaultChainConfigSorted()
   523  	set := SetCacheChainConfig(&SufficientChainConfig{ChainConfig: c})
   524  
   525  	if set == nil {
   526  		t.Fatal("set returned nil")
   527  	}
   528  
   529  	got := GetCacheChainConfig()
   530  	if got == nil {
   531  		t.Fatal("get returned nil")
   532  	}
   533  
   534  	// create new "checkpoint" fork for testing
   535  	checkpoint := &Fork{
   536  		Name:         "checkpoint",
   537  		Block:        big.NewInt(1930000),
   538  		RequiredHash: common.HexToHash("0xabc65e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ad123"),
   539  	}
   540  	c.Forks = append(c.Forks, checkpoint)
   541  
   542  	got.ChainConfig.Forks = c.Forks
   543  	didSet := SetCacheChainConfig(got)
   544  	if !reflect.DeepEqual(got, didSet) {
   545  		t.Errorf("got: %v, want: %v", didSet, got)
   546  	}
   547  
   548  	if f := set.ChainConfig.ForkByName("checkpoint"); f == nil {
   549  		t.Errorf("got: %v, want: %v", f, checkpoint)
   550  	}
   551  }
   552  
   553  func TestChainConfig_GetLastRequiredHashFork(t *testing.T) {
   554  	c := getDefaultChainConfigSorted()
   555  
   556  	daoFork := c.ForkByName("The DAO Hard Fork")
   557  	got, want := c.GetLatestRequiredHashFork(big.NewInt(1920000)), daoFork
   558  
   559  	// sanity check
   560  	if want == nil {
   561  		t.Fatal("nil want hard fork")
   562  	}
   563  
   564  	if got == nil {
   565  		t.Fatalf("got: %v, want: %s", got, want.Name)
   566  	}
   567  	if got.RequiredHash.Hex() != "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" {
   568  		t.Errorf("got: %v, want: %s", got, got.RequiredHash.Hex())
   569  	}
   570  	if got.Block.Cmp(big.NewInt(1920000)) != 0 {
   571  		t.Errorf("got: %d, want: %d", got.Block, 1920000)
   572  	}
   573  
   574  	// create new "checkpoint" fork for testing
   575  	checkpoint := &Fork{
   576  		Name:         "checkpoint",
   577  		Block:        big.NewInt(1930000),
   578  		RequiredHash: common.HexToHash("0xabc65e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ad123"),
   579  	}
   580  	c.Forks = append(c.Forks, checkpoint)
   581  
   582  	// Noting that config forks do not have to be sorted for this function to work.
   583  	//c.SortForks()
   584  
   585  	got, want = c.GetLatestRequiredHashFork(big.NewInt(1930000)), checkpoint
   586  	if !reflect.DeepEqual(got, want) {
   587  		t.Errorf("got: %v, want: %v", got, want)
   588  	}
   589  
   590  	// should use dao fork, not checkpoint since block n has not reached checkpoint
   591  	got, want = c.GetLatestRequiredHashFork(big.NewInt(1920001)), daoFork
   592  	if !reflect.DeepEqual(got, want) {
   593  		t.Errorf("got: %v, want: %v", got, want)
   594  	}
   595  }
   596  
   597  func TestChainConfig_GetSigner(t *testing.T) {
   598  	c := getDefaultChainConfigSorted()
   599  	var forkBlocks []*big.Int
   600  	for _, fork := range c.Forks {
   601  		forkBlocks = append(forkBlocks, fork.Block)
   602  	}
   603  
   604  	blockMinus := big.NewInt(-2)
   605  	blockPlus := big.NewInt(2)
   606  
   607  	for _, block := range forkBlocks {
   608  		bottom := big.NewInt(0).Add(block, blockMinus)
   609  		top := big.NewInt(0).Add(block, blockPlus)
   610  		current := bottom
   611  		for current.Cmp(top) <= 0 {
   612  			signer := c.GetSigner(current)
   613  			feat, _, configured := c.GetFeature(current, "eip155")
   614  			if !configured {
   615  				if !signer.Equal(types.BasicSigner{}) {
   616  					t.Errorf("expected basic signer, block: %v", current)
   617  				}
   618  			} else {
   619  				cid, ok := feat.GetBigInt("chainID")
   620  				if !ok {
   621  					t.Errorf("unexpected missing eip155 chainid, block: %v", current)
   622  				}
   623  				shouldb := types.NewChainIdSigner(cid)
   624  				if !signer.Equal(shouldb) {
   625  					t.Errorf("want: %v, got: %v", shouldb, current)
   626  				}
   627  			}
   628  			current = big.NewInt(0).Add(current, big.NewInt(1))
   629  		}
   630  	}
   631  
   632  }
   633  
   634  func TestResolvePath(t *testing.T) {
   635  	cases := []struct {
   636  		args []string
   637  		want string
   638  	}{
   639  		{
   640  			args: []string{"./a/b/config.csv", "."},
   641  			want: filepath.Clean("a/b/config.csv"),
   642  		},
   643  		{
   644  			args: []string{"./a/b/config.csv", ""},
   645  			want: filepath.Clean("a/b/config.csv"),
   646  		},
   647  		{
   648  			args: []string{"./a/b/config.csv", "./a/b/config.json"},
   649  			want: filepath.Clean("a/b/a/b/config.csv"),
   650  		},
   651  		{
   652  			args: []string{"config.csv", "a/b"},
   653  			want: filepath.Clean("a/config.csv"), // since resolvePath expects b|config.csv to be adjacent (neighboring filepaths), ie. 'b' should be a file
   654  		},
   655  		{
   656  			args: []string{"config.csv", "a/b/config.json"},
   657  			want: filepath.Clean("a/b/config.csv"),
   658  		},
   659  		{
   660  			args: []string{"test.txt", "some/dir/conf.json"},
   661  			want: filepath.Clean("some/dir/test.txt"),
   662  		},
   663  		{
   664  			args: []string{"test.txt", "./some/dir/conf.json"},
   665  			want: filepath.Clean("some/dir/test.txt"),
   666  		},
   667  		{
   668  			args: []string{"./test.txt", "some/dir/conf.json"},
   669  			want: filepath.Clean("some/dir/test.txt"),
   670  		},
   671  		{
   672  			args: []string{"./test.txt", "./some/dir/conf.json"},
   673  			want: filepath.Clean("some/dir/test.txt"),
   674  		},
   675  		{
   676  			args: []string{"../test.txt", "some/dir/conf.json"},
   677  			want: filepath.Clean("some/test.txt"),
   678  		},
   679  		{
   680  			args: []string{"../test.txt", "/some/dir/conf.json"},
   681  			want: filepath.Clean("/some/test.txt"),
   682  		},
   683  		{
   684  			args: []string{"../test.txt", "some/dir/.././conf.json"},
   685  			want: filepath.Clean("test.txt"),
   686  		},
   687  		{
   688  			args: []string{"../test.txt", "conf.json"},
   689  			want: filepath.Clean("../test.txt"),
   690  		},
   691  		{
   692  			args: []string{"../../../../a/b/c/d/test.txt", "conf.json"},
   693  			want: filepath.Clean("../../../../a/b/c/d/test.txt"),
   694  		},
   695  		{
   696  			args: []string{"../../../../a/b/c/d/test.txt", "a/b/c/d/conf.json"},
   697  			want: filepath.Clean("a/b/c/d/test.txt"),
   698  		},
   699  	}
   700  	for _, c := range cases {
   701  		t.Run(c.args[0]+"+"+c.args[1], func(t *testing.T) {
   702  			if got := resolvePath(c.args[0], c.args[1]); got != c.want {
   703  				t.Errorf("got: %v, want: %v", got, c.want)
   704  			}
   705  		})
   706  	}
   707  }
   708  
   709  func makeOKSufficientChainConfig(dump *GenesisDump, config *ChainConfig) *SufficientChainConfig {
   710  	// Setup.
   711  	whole := &SufficientChainConfig{}
   712  	whole.Identity = "testID"
   713  	whole.Network = 3
   714  	whole.Name = "testable"
   715  	whole.Consensus = "ethash"
   716  	whole.Genesis = dump
   717  	whole.ChainConfig = config
   718  	whole.Bootstrap = []string{
   719  		"enode://e809c4a2fec7daed400e5e28564e23693b23b2cc5a019b612505631bbe7b9ccf709c1796d2a3d29ef2b045f210caf51e3c4f5b6d3587d43ad5d6397526fa6179@174.112.32.157:30303",
   720  		"enode://6e538e7c1280f0a31ff08b382db5302480f775480b8e68f8febca0ceff81e4b19153c6f8bf60313b93bef2cc34d34e1df41317de0ce613a201d1660a788a03e2@52.206.67.235:30303",
   721  		"enode://5fbfb426fbb46f8b8c1bd3dd140f5b511da558cd37d60844b525909ab82e13a25ee722293c829e52cb65c2305b1637fa9a2ea4d6634a224d5f400bfe244ac0de@162.243.55.45:30303",
   722  		"enode://42d8f29d1db5f4b2947cd5c3d76c6d0d3697e6b9b3430c3d41e46b4bb77655433aeedc25d4b4ea9d8214b6a43008ba67199374a9b53633301bca0cd20c6928ab@104.155.176.151:30303",
   723  		"enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303",
   724  		"enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303",
   725  		"enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303",
   726  		"enode://39abab9d2a41f53298c0c9dc6bbca57b0840c3ba9dccf42aa27316addc1b7e56ade32a0a9f7f52d6c5db4fe74d8824bcedfeaecf1a4e533cacb71cf8100a9442@144.76.238.49:30303",
   727  		"enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306",
   728  	}
   729  	return whole
   730  }
   731  
   732  // TestSufficientChainConfig_IsValid tests against defaulty dumps and chainconfigs.
   733  func TestSufficientChainConfig_IsValid(t *testing.T) {
   734  	dumps := []*GenesisDump{DefaultConfigMainnet.Genesis, DefaultConfigMorden.Genesis}
   735  	configs := []*ChainConfig{DefaultConfigMainnet.ChainConfig, DefaultConfigMorden.ChainConfig}
   736  
   737  	for i, dump := range dumps {
   738  		for j, config := range configs {
   739  			// Make sure initial ok config is ok.
   740  			scc := makeOKSufficientChainConfig(dump, config)
   741  			if s, ok := scc.IsValid(); !ok {
   742  				t.Errorf("unexpected notok: %v @ %v/%v", s, i, j)
   743  			}
   744  
   745  			// Remove each required field and ensure is NOT ok.
   746  			o1 := scc.Identity
   747  			scc.Identity = ""
   748  			if s, ok := scc.IsValid(); ok {
   749  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   750  			}
   751  			scc.Identity = o1
   752  
   753  			o2 := scc.Network
   754  			scc.Network = 0
   755  			if s, ok := scc.IsValid(); ok {
   756  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   757  			}
   758  			scc.Network = o2
   759  
   760  			o3 := scc.Consensus
   761  			scc.Consensus = "asdf"
   762  			if s, ok := scc.IsValid(); ok {
   763  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   764  			}
   765  			scc.Consensus = o3
   766  
   767  			o4 := scc.Consensus
   768  			scc.Consensus = ""
   769  			if s, ok := scc.IsValid(); ok {
   770  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   771  			}
   772  			scc.Consensus = o4
   773  
   774  			o := scc.Genesis
   775  			scc.Genesis = nil
   776  			if s, ok := scc.IsValid(); ok {
   777  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   778  			}
   779  			scc.Genesis = o
   780  
   781  			oo := scc.ChainConfig
   782  			scc.ChainConfig = nil
   783  			if s, ok := scc.IsValid(); ok {
   784  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   785  			}
   786  			scc.ChainConfig = oo
   787  
   788  			ooo := scc.Bootstrap
   789  			scc.Bootstrap = []string{}
   790  			if s, ok := scc.IsValid(); !ok {
   791  				t.Errorf("unexpected notok: %v @ %v/%v", s, i, j)
   792  			}
   793  			scc.Bootstrap = ooo
   794  
   795  			oooo := scc.Genesis.Nonce
   796  			scc.Genesis.Nonce = ""
   797  			if s, ok := scc.IsValid(); ok {
   798  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   799  			}
   800  			scc.Genesis.Nonce = oooo
   801  
   802  			ooooo := scc.Genesis.Nonce
   803  			scc.Genesis.Nonce = "0xasdf"
   804  			if s, ok := scc.IsValid(); ok {
   805  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   806  			}
   807  			scc.Genesis.Nonce = ooooo
   808  
   809  			oooooo := scc.Genesis.GasLimit
   810  			scc.Genesis.GasLimit = "0xasdf"
   811  			if s, ok := scc.IsValid(); ok {
   812  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   813  			}
   814  			scc.Genesis.GasLimit = oooooo
   815  
   816  			ooooooo0 := scc.Genesis.Difficulty
   817  			scc.Genesis.Difficulty = "0xasdf"
   818  			if s, ok := scc.IsValid(); ok {
   819  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   820  			}
   821  			scc.Genesis.Difficulty = ooooooo0
   822  
   823  			ooooooo00 := scc.ChainConfig.Forks
   824  			scc.ChainConfig.Forks = []*Fork{}
   825  			if s, ok := scc.IsValid(); ok {
   826  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   827  			}
   828  			scc.ChainConfig.Forks = ooooooo00
   829  
   830  			ooooooo1 := scc.ChainConfig.Forks
   831  			scc.ChainConfig.Forks = nil
   832  			if s, ok := scc.IsValid(); ok {
   833  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   834  			}
   835  			scc.ChainConfig.Forks = ooooooo1
   836  
   837  			scc = &SufficientChainConfig{}
   838  			if s, ok := scc.IsValid(); ok {
   839  				t.Errorf("unexpected ok: %v @ %v/%v", s, i, j)
   840  			}
   841  		}
   842  	}
   843  }
   844  
   845  func TestGenesisAllocationError(t *testing.T) {
   846  	_, err := parseExternalChainConfig("testdata/test.json", func(path string) (io.ReadCloser, error) { return os.Open(path) })
   847  	if err == nil {
   848  		t.Error("expected error, got nil")
   849  	}
   850  	if !strings.Contains(err.Error(), "\"alloc\" values already set") {
   851  		t.Error("invalid error message")
   852  	}
   853  }