aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustav Simonsson <gustav.simonsson@gmail.com>2015-03-04 01:41:51 +0800
committerGustav Simonsson <gustav.simonsson@gmail.com>2015-03-05 03:27:09 +0800
commit871dfd399be8ee657109112d527645c2c1b3a8f9 (patch)
tree8daf0d07fdd308b55302dcbf11845657b97883e8
parent15f491e5007d1507f20d0edce36cc9c0bd5cbd37 (diff)
downloaddexon-871dfd399be8ee657109112d527645c2c1b3a8f9.tar.gz
dexon-871dfd399be8ee657109112d527645c2c1b3a8f9.tar.zst
dexon-871dfd399be8ee657109112d527645c2c1b3a8f9.zip
Add initial implementation of block tests
* Add blocktest cmd and support for block tests files in tests/BlockTests , the launched node does not connect to network, resets state with a genesis block from the test file and starts the RPC API
-rw-r--r--cmd/blocktest/flags.go41
-rw-r--r--cmd/blocktest/main.go320
-rw-r--r--core/chain_manager.go15
-rw-r--r--core/error.go2
4 files changed, 377 insertions, 1 deletions
diff --git a/cmd/blocktest/flags.go b/cmd/blocktest/flags.go
new file mode 100644
index 000000000..c811e5b85
--- /dev/null
+++ b/cmd/blocktest/flags.go
@@ -0,0 +1,41 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ go-ethereum 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @authors
+ * Gustav Simonsson <gustav.simonsson@gmail.com>
+ */
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+)
+
+var (
+ TestFile string
+)
+
+func Init() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, "%s <testfile>\n", os.Args[0])
+ flag.PrintDefaults()
+ }
+ flag.Parse()
+
+ TestFile = flag.Arg(0)
+}
diff --git a/cmd/blocktest/main.go b/cmd/blocktest/main.go
new file mode 100644
index 000000000..4a05b8bee
--- /dev/null
+++ b/cmd/blocktest/main.go
@@ -0,0 +1,320 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum 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.
+
+ go-ethereum 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 General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @authors
+ * Gustav Simonsson <gustav.simonsson@gmail.com>
+ * @date 2015
+ *
+ */
+
+package main
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "math/big"
+ "path"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ types "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/p2p/nat"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+const (
+ ClientIdentifier = "Ethereum(G)"
+ Version = "0.8.6"
+)
+
+type Account struct {
+ Balance string
+ Code string
+ Nonce string
+ Storage map[string]string
+}
+
+type BlockHeader struct {
+ Bloom string
+ Coinbase string
+ Difficulty string
+ ExtraData string
+ GasLimit string
+ GasUsed string
+ MixHash string
+ Nonce string
+ Number string
+ ParentHash string
+ ReceiptTrie string
+ SeedHash string
+ StateRoot string
+ Timestamp string
+ TransactionsTrie string
+ UncleHash string
+}
+type Tx struct {
+ Data string
+ GasLimit string
+ GasPrice string
+ Nonce string
+ R string
+ S string
+ To string
+ V string
+ Value string
+}
+
+type Block struct {
+ BlockHeader BlockHeader
+ Rlp string
+ Transactions []Tx
+ UncleHeaders []string
+}
+
+type Test struct {
+ Blocks []Block
+ GenesisBlockHeader BlockHeader
+ Pre map[string]Account
+}
+
+var (
+ Identifier string
+ KeyRing string
+ DiffTool bool
+ DiffType string
+ KeyStore string
+ StartRpc bool
+ StartWebSockets bool
+ RpcListenAddress string
+ RpcPort int
+ WsPort int
+ OutboundPort string
+ ShowGenesis bool
+ AddPeer string
+ MaxPeer int
+ GenAddr bool
+ BootNodes string
+ NodeKey *ecdsa.PrivateKey
+ NAT nat.Interface
+ SecretFile string
+ ExportDir string
+ NonInteractive bool
+ Datadir string
+ LogFile string
+ ConfigFile string
+ DebugFile string
+ LogLevel int
+ LogFormat string
+ Dump bool
+ DumpHash string
+ DumpNumber int
+ VmType int
+ ImportChain string
+ SHH bool
+ Dial bool
+ PrintVersion bool
+ MinerThreads int
+)
+
+// flags specific to cli client
+var (
+ StartMining bool
+ StartJsConsole bool
+ InputFile string
+)
+
+func main() {
+ init_vars()
+
+ Init()
+
+ if len(TestFile) < 1 {
+ log.Fatal("Please specify test file")
+ }
+ blocks, err := loadBlocksFromTestFile(TestFile)
+ if err != nil {
+ panic(err)
+ }
+
+ runtime.GOMAXPROCS(runtime.NumCPU())
+
+ defer func() {
+ logger.Flush()
+ }()
+
+ utils.HandleInterrupt()
+
+ utils.InitConfig(VmType, ConfigFile, Datadir, "ethblocktest")
+
+ ethereum, err := eth.New(&eth.Config{
+ Name: p2p.MakeName(ClientIdentifier, Version),
+ KeyStore: KeyStore,
+ DataDir: Datadir,
+ LogFile: LogFile,
+ LogLevel: LogLevel,
+ LogFormat: LogFormat,
+ MaxPeers: MaxPeer,
+ Port: OutboundPort,
+ NAT: NAT,
+ KeyRing: KeyRing,
+ Shh: true,
+ Dial: Dial,
+ BootNodes: BootNodes,
+ NodeKey: NodeKey,
+ MinerThreads: MinerThreads,
+ })
+
+ utils.StartRpc(ethereum, RpcListenAddress, RpcPort)
+ utils.StartEthereum(ethereum)
+
+ ethereum.ChainManager().ResetWithGenesisBlock(blocks[0])
+
+ // fmt.Println("HURR: ", hex.EncodeToString(ethutil.Encode(blocks[0].RlpData())))
+
+ go ethereum.ChainManager().InsertChain(types.Blocks{blocks[1]})
+ fmt.Println("OK! ")
+ ethereum.WaitForShutdown()
+}
+
+func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
+ fileContent, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ return
+ }
+ bt := *new(map[string]Test)
+ err = json.Unmarshal(fileContent, &bt)
+ if err != nil {
+ return
+ }
+
+ // TODO: support multiple blocks; loop over all blocks
+ gbh := new(types.Header)
+
+ // Let's use slighlty different namings for the same things, because that's awesome.
+ gbh.ParentHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.ParentHash)
+ gbh.UncleHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.UncleHash)
+ gbh.Coinbase, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.Coinbase)
+ gbh.Root, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.StateRoot)
+ gbh.TxHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.TransactionsTrie)
+ gbh.ReceiptHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.ReceiptTrie)
+ gbh.Bloom, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.Bloom)
+
+ gbh.MixDigest, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.MixHash)
+ gbh.SeedHash, err = hex_decode(bt["SimpleTx"].GenesisBlockHeader.SeedHash)
+
+ d, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Difficulty, 10)
+ gbh.Difficulty = d
+
+ n, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Number, 10)
+ gbh.Number = n
+
+ gl, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.GasLimit, 10)
+ gbh.GasLimit = gl
+
+ gu, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.GasUsed, 10)
+ gbh.GasUsed = gu
+
+ ts, _ := new(big.Int).SetString(bt["SimpleTx"].GenesisBlockHeader.Timestamp, 0)
+ gbh.Time = ts.Uint64()
+
+ extra, err := hex_decode(bt["SimpleTx"].GenesisBlockHeader.ExtraData)
+ gbh.Extra = string(extra) // TODO: change ExtraData to byte array
+
+ nonce, _ := hex_decode(bt["SimpleTx"].GenesisBlockHeader.Nonce)
+ gbh.Nonce = nonce
+
+ if err != nil {
+ return
+ }
+
+ gb := types.NewBlockWithHeader(gbh)
+ gb.Reward = new(big.Int)
+
+ testBlock := new(types.Block)
+
+ rlpBytes, err := hex_decode(bt["SimpleTx"].Blocks[0].Rlp)
+ err = rlp.Decode(bytes.NewReader(rlpBytes), &testBlock)
+ if err != nil {
+ return
+ }
+
+ blocks = types.Blocks{
+ gb,
+ testBlock,
+ }
+
+ return
+}
+
+func init_vars() {
+ VmType = 0
+ Identifier = ""
+ KeyRing = ""
+ KeyStore = "db"
+ RpcListenAddress = "127.0.0.1"
+ RpcPort = 8545
+ WsPort = 40404
+ StartRpc = true
+ StartWebSockets = false
+ NonInteractive = false
+ GenAddr = false
+ SecretFile = ""
+ ExportDir = ""
+ LogFile = ""
+
+ timeStr := strconv.FormatInt(time.Now().UnixNano(), 10)
+
+ Datadir = path.Join(ethutil.DefaultDataDir(), timeStr)
+ ConfigFile = path.Join(ethutil.DefaultDataDir(), timeStr, "conf.ini")
+
+ DebugFile = ""
+ LogLevel = 5
+ LogFormat = "std"
+ DiffTool = false
+ DiffType = "all"
+ ShowGenesis = false
+ ImportChain = ""
+ Dump = false
+ DumpHash = ""
+ DumpNumber = -1
+ StartMining = false
+ StartJsConsole = false
+ PrintVersion = false
+ MinerThreads = runtime.NumCPU()
+
+ Dial = false
+ OutboundPort = "30303"
+ BootNodes = ""
+ MaxPeer = 1
+
+}
+
+func hex_decode(s string) (res []byte, err error) {
+ return hex.DecodeString(strings.TrimPrefix(s, "0x"))
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index f2382cf8d..17bfb1f3e 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -231,6 +231,21 @@ func (bc *ChainManager) Reset() {
bc.setTotalDifficulty(ethutil.Big("0"))
}
+func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
+ bc.mu.Lock()
+ defer bc.mu.Unlock()
+
+ for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
+ bc.db.Delete(block.Hash())
+ }
+
+ // Prepare the genesis block
+ bc.genesisBlock = gb
+ bc.write(bc.genesisBlock)
+ bc.insert(bc.genesisBlock)
+ bc.currentBlock = bc.genesisBlock
+}
+
func (self *ChainManager) Export() []byte {
self.mu.RLock()
defer self.mu.RUnlock()
diff --git a/core/error.go b/core/error.go
index fb1eaed84..514cd076b 100644
--- a/core/error.go
+++ b/core/error.go
@@ -22,7 +22,7 @@ func (err *ParentErr) Error() string {
}
func ParentError(hash []byte) error {
- return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)}
+ return &ParentErr{Message: fmt.Sprintf("Block's parent unknown %x", hash)}
}
func IsParentErr(err error) bool {