github.com/calmw/ethereum@v0.1.1/cmd/geth/genesis_test.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"testing"
    25  )
    26  
    27  var customGenesisTests = []struct {
    28  	genesis string
    29  	query   string
    30  	result  string
    31  }{
    32  	// Genesis file with an empty chain configuration (ensure missing fields work)
    33  	{
    34  		genesis: `{
    35  			"alloc"      : {},
    36  			"coinbase"   : "0x0000000000000000000000000000000000000000",
    37  			"difficulty" : "0x20000",
    38  			"extraData"  : "",
    39  			"gasLimit"   : "0x2fefd8",
    40  			"nonce"      : "0x0000000000001338",
    41  			"mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
    42  			"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    43  			"timestamp"  : "0x00",
    44  			"config"     : {
    45  				"terminalTotalDifficultyPassed": true
    46  			}
    47  		}`,
    48  		query:  "eth.getBlock(0).nonce",
    49  		result: "0x0000000000001338",
    50  	},
    51  	// Genesis file with specific chain configurations
    52  	{
    53  		genesis: `{
    54  			"alloc"      : {},
    55  			"coinbase"   : "0x0000000000000000000000000000000000000000",
    56  			"difficulty" : "0x20000",
    57  			"extraData"  : "",
    58  			"gasLimit"   : "0x2fefd8",
    59  			"nonce"      : "0x0000000000001339",
    60  			"mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
    61  			"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    62  			"timestamp"  : "0x00",
    63  			"config"     : {
    64  				"homesteadBlock"                : 42,
    65  				"daoForkBlock"                  : 141,
    66  				"daoForkSupport"                : true,
    67  				"terminalTotalDifficultyPassed" : true
    68  			}
    69  		}`,
    70  		query:  "eth.getBlock(0).nonce",
    71  		result: "0x0000000000001339",
    72  	},
    73  }
    74  
    75  // Tests that initializing Geth with a custom genesis block and chain definitions
    76  // work properly.
    77  func TestCustomGenesis(t *testing.T) {
    78  	t.Parallel()
    79  	for i, tt := range customGenesisTests {
    80  		// Create a temporary data directory to use and inspect later
    81  		datadir := t.TempDir()
    82  
    83  		// Initialize the data directory with the custom genesis block
    84  		json := filepath.Join(datadir, "genesis.json")
    85  		if err := os.WriteFile(json, []byte(tt.genesis), 0600); err != nil {
    86  			t.Fatalf("test %d: failed to write genesis file: %v", i, err)
    87  		}
    88  		runGeth(t, "--datadir", datadir, "init", json).WaitExit()
    89  
    90  		// Query the custom genesis block
    91  		geth := runGeth(t, "--networkid", "1337", "--syncmode=full", "--cache", "16",
    92  			"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
    93  			"--nodiscover", "--nat", "none", "--ipcdisable",
    94  			"--exec", tt.query, "console")
    95  		geth.ExpectRegexp(tt.result)
    96  		geth.ExpectExit()
    97  	}
    98  }
    99  
   100  // TestCustomBackend that the backend selection and detection (leveldb vs pebble) works properly.
   101  func TestCustomBackend(t *testing.T) {
   102  	t.Parallel()
   103  	// Test pebble, but only on 64-bit platforms
   104  	if strconv.IntSize != 64 {
   105  		t.Skip("Custom backends are only available on 64-bit platform")
   106  	}
   107  	genesis := `{
   108  		"alloc"      : {},
   109  		"coinbase"   : "0x0000000000000000000000000000000000000000",
   110  			"difficulty" : "0x20000",
   111  			"extraData"  : "",
   112  			"gasLimit"   : "0x2fefd8",
   113  			"nonce"      : "0x0000000000001338",
   114  			"mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
   115  			"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
   116  			"timestamp"  : "0x00",
   117  			"config"     : {
   118  				"terminalTotalDifficultyPassed": true
   119  			}
   120  		}`
   121  	type backendTest struct {
   122  		initArgs   []string
   123  		initExpect string
   124  		execArgs   []string
   125  		execExpect string
   126  	}
   127  	testfunc := func(t *testing.T, tt backendTest) error {
   128  		// Create a temporary data directory to use and inspect later
   129  		datadir := t.TempDir()
   130  
   131  		// Initialize the data directory with the custom genesis block
   132  		json := filepath.Join(datadir, "genesis.json")
   133  		if err := os.WriteFile(json, []byte(genesis), 0600); err != nil {
   134  			return fmt.Errorf("failed to write genesis file: %v", err)
   135  		}
   136  		{ // Init
   137  			args := append(tt.initArgs, "--datadir", datadir, "init", json)
   138  			geth := runGeth(t, args...)
   139  			geth.ExpectRegexp(tt.initExpect)
   140  			geth.ExpectExit()
   141  		}
   142  		{ // Exec + query
   143  			args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16",
   144  				"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
   145  				"--nodiscover", "--nat", "none", "--ipcdisable",
   146  				"--exec", "eth.getBlock(0).nonce", "console")
   147  			geth := runGeth(t, args...)
   148  			geth.ExpectRegexp(tt.execExpect)
   149  			geth.ExpectExit()
   150  		}
   151  		return nil
   152  	}
   153  	for i, tt := range []backendTest{
   154  		{ // When not specified, it should default to pebble
   155  			execArgs:   []string{"--db.engine", "pebble"},
   156  			execExpect: "0x0000000000001338",
   157  		},
   158  		{ // Explicit leveldb
   159  			initArgs:   []string{"--db.engine", "leveldb"},
   160  			execArgs:   []string{"--db.engine", "leveldb"},
   161  			execExpect: "0x0000000000001338",
   162  		},
   163  		{ // Explicit leveldb first, then autodiscover
   164  			initArgs:   []string{"--db.engine", "leveldb"},
   165  			execExpect: "0x0000000000001338",
   166  		},
   167  		{ // Explicit pebble
   168  			initArgs:   []string{"--db.engine", "pebble"},
   169  			execArgs:   []string{"--db.engine", "pebble"},
   170  			execExpect: "0x0000000000001338",
   171  		},
   172  		{ // Explicit pebble, then auto-discover
   173  			initArgs:   []string{"--db.engine", "pebble"},
   174  			execExpect: "0x0000000000001338",
   175  		},
   176  		{ // Can't start pebble on top of leveldb
   177  			initArgs:   []string{"--db.engine", "leveldb"},
   178  			execArgs:   []string{"--db.engine", "pebble"},
   179  			execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`,
   180  		},
   181  		{ // Can't start leveldb on top of pebble
   182  			initArgs:   []string{"--db.engine", "pebble"},
   183  			execArgs:   []string{"--db.engine", "leveldb"},
   184  			execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`,
   185  		},
   186  		{ // Reject invalid backend choice
   187  			initArgs:   []string{"--db.engine", "mssql"},
   188  			initExpect: `Fatal: Invalid choice for db.engine 'mssql', allowed 'leveldb' or 'pebble'`,
   189  			// Since the init fails, this will return the (default) mainnet genesis
   190  			// block nonce
   191  			execExpect: `0x0000000000000042`,
   192  		},
   193  	} {
   194  		if err := testfunc(t, tt); err != nil {
   195  			t.Fatalf("test %d-leveldb: %v", i, err)
   196  		}
   197  	}
   198  }