瀏覽代碼

Add tests for uncle timestamps and refactor timestamp type

Gustav Simonsson 10 年之前
父節點
當前提交
7324176f70

+ 3 - 3
cmd/evm/main.go

@@ -166,7 +166,7 @@ type VMEnv struct {
 
 	depth int
 	Gas   *big.Int
-	time  uint64
+	time  *big.Int
 	logs  []vm.StructLog
 }
 
@@ -175,7 +175,7 @@ func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VM
 		state:      state,
 		transactor: &transactor,
 		value:      value,
-		time:       uint64(time.Now().Unix()),
+		time:       big.NewInt(time.Now().Unix()),
 	}
 }
 
@@ -183,7 +183,7 @@ func (self *VMEnv) State() *state.StateDB    { return self.state }
 func (self *VMEnv) Origin() common.Address   { return *self.transactor }
 func (self *VMEnv) BlockNumber() *big.Int    { return common.Big0 }
 func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
-func (self *VMEnv) Time() uint64             { return self.time }
+func (self *VMEnv) Time() *big.Int           { return self.time }
 func (self *VMEnv) Difficulty() *big.Int     { return common.Big1 }
 func (self *VMEnv) BlockHash() []byte        { return make([]byte, 32) }
 func (self *VMEnv) Value() *big.Int          { return self.value }

+ 13 - 7
core/block_processor.go

@@ -203,7 +203,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
 	txs := block.Transactions()
 
 	// Block validation
-	if err = ValidateHeader(sm.Pow, header, parent, false); err != nil {
+	if err = ValidateHeader(sm.Pow, header, parent, false, false); err != nil {
 		return
 	}
 
@@ -327,7 +327,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
 			return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
 		}
 
-		if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash], true); err != nil {
+		if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash], true, true); err != nil {
 			return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
 		}
 	}
@@ -358,19 +358,25 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
 
 // See YP section 4.3.4. "Block Header Validity"
 // Validates a block. Returns an error if the block is invalid.
-func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow bool) error {
+func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow, uncle bool) error {
 	if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
 		return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
 	}
 
-	if block.Time > uint64(time.Now().Unix()) {
-		return BlockFutureErr
+	if uncle {
+		if block.Time.Cmp(common.MaxBig) == 1 {
+			return BlockTSTooBigErr
+		}
+	} else {
+		if block.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 {
+			return BlockFutureErr
+		}
 	}
-	if block.Time <= parent.Time() {
+	if block.Time.Cmp(parent.Time()) != 1 {
 		return BlockEqualTSErr
 	}
 
-	expd := CalcDifficulty(block.Time, parent.Time(), parent.Number(), parent.Difficulty())
+	expd := CalcDifficulty(block.Time.Uint64(), parent.Time().Uint64(), parent.Number(), parent.Difficulty())
 	if expd.Cmp(block.Difficulty) != 0 {
 		return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
 	}

+ 2 - 2
core/block_processor_test.go

@@ -48,13 +48,13 @@ func TestNumber(t *testing.T) {
 	statedb := state.New(chain.Genesis().Root(), chain.chainDb)
 	header := makeHeader(chain.Genesis(), statedb)
 	header.Number = big.NewInt(3)
-	err := ValidateHeader(pow, header, chain.Genesis(), false)
+	err := ValidateHeader(pow, header, chain.Genesis(), false, false)
 	if err != BlockNumberErr {
 		t.Errorf("expected block number error, got %q", err)
 	}
 
 	header = makeHeader(chain.Genesis(), statedb)
-	err = ValidateHeader(pow, header, chain.Genesis(), false)
+	err = ValidateHeader(pow, header, chain.Genesis(), false, false)
 	if err == BlockNumberErr {
 		t.Errorf("didn't expect block number error")
 	}

+ 8 - 3
core/chain_makers.go

@@ -166,16 +166,21 @@ func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int,
 }
 
 func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
-	time := parent.Time() + 10 // block time is fixed at 10 seconds
+	var time *big.Int
+	if parent.Time() == nil {
+		time = big.NewInt(10)
+	} else {
+		time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
+	}
 	return &types.Header{
 		Root:       state.Root(),
 		ParentHash: parent.Hash(),
 		Coinbase:   parent.Coinbase(),
-		Difficulty: CalcDifficulty(time, parent.Time(), parent.Number(), parent.Difficulty()),
+		Difficulty: CalcDifficulty(time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
 		GasLimit:   CalcGasLimit(parent),
 		GasUsed:    new(big.Int),
 		Number:     new(big.Int).Add(parent.Number(), common.Big1),
-		Time:       uint64(time),
+		Time:       time,
 	}
 }
 

+ 2 - 1
core/chain_manager.go

@@ -596,7 +596,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
 				// Allow up to MaxFuture second in the future blocks. If this limit
 				// is exceeded the chain is discarded and processed at a later time
 				// if given.
-				if max := uint64(time.Now().Unix()) + maxTimeFutureBlocks; block.Time() > max {
+				max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks)
+				if block.Time().Cmp(max) == 1 {
 					return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max)
 				}
 

+ 4 - 3
core/error.go

@@ -25,9 +25,10 @@ import (
 )
 
 var (
-	BlockNumberErr  = errors.New("block number invalid")
-	BlockFutureErr  = errors.New("block time is in the future")
-	BlockEqualTSErr = errors.New("block time stamp equal to previous")
+	BlockNumberErr   = errors.New("block number invalid")
+	BlockFutureErr   = errors.New("block time is in the future")
+	BlockTSTooBigErr = errors.New("block time too big")
+	BlockEqualTSErr  = errors.New("block time stamp equal to previous")
 )
 
 // Parent error. In case a parent is unknown this error will be thrown

+ 1 - 1
core/genesis.go

@@ -73,7 +73,7 @@ func WriteGenesisBlock(chainDb common.Database, reader io.Reader) (*types.Block,
 	difficulty := common.String2Big(genesis.Difficulty)
 	block := types.NewBlock(&types.Header{
 		Nonce:      types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()),
-		Time:       common.String2Big(genesis.Timestamp).Uint64(),
+		Time:       common.String2Big(genesis.Timestamp),
 		ParentHash: common.HexToHash(genesis.ParentHash),
 		Extra:      common.FromHex(genesis.ExtraData),
 		GasLimit:   common.String2Big(genesis.GasLimit),

+ 6 - 3
core/types/block.go

@@ -60,7 +60,7 @@ type Header struct {
 	Number      *big.Int       // The block number
 	GasLimit    *big.Int       // Gas limit
 	GasUsed     *big.Int       // Gas used
-	Time        uint64         // Creation time
+	Time        *big.Int       // Creation time
 	Extra       []byte         // Extra data
 	MixDigest   common.Hash    // for quick difficulty verification
 	Nonce       BlockNonce
@@ -94,7 +94,7 @@ func (h *Header) UnmarshalJSON(data []byte) error {
 		Coinbase   string
 		Difficulty string
 		GasLimit   string
-		Time       uint64
+		Time       *big.Int
 		Extra      string
 	}
 	dec := json.NewDecoder(bytes.NewReader(data))
@@ -210,6 +210,9 @@ func NewBlockWithHeader(header *Header) *Block {
 
 func copyHeader(h *Header) *Header {
 	cpy := *h
+	if cpy.Time = new(big.Int); h.Time != nil {
+		cpy.Time.Set(h.Time)
+	}
 	if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
 		cpy.Difficulty.Set(h.Difficulty)
 	}
@@ -301,13 +304,13 @@ func (b *Block) Number() *big.Int     { return new(big.Int).Set(b.header.Number)
 func (b *Block) GasLimit() *big.Int   { return new(big.Int).Set(b.header.GasLimit) }
 func (b *Block) GasUsed() *big.Int    { return new(big.Int).Set(b.header.GasUsed) }
 func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
+func (b *Block) Time() *big.Int       { return new(big.Int).Set(b.header.Time) }
 
 func (b *Block) NumberU64() uint64        { return b.header.Number.Uint64() }
 func (b *Block) MixDigest() common.Hash   { return b.header.MixDigest }
 func (b *Block) Nonce() uint64            { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
 func (b *Block) Bloom() Bloom             { return b.header.Bloom }
 func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
-func (b *Block) Time() uint64             { return b.header.Time }
 func (b *Block) Root() common.Hash        { return b.header.Root }
 func (b *Block) ParentHash() common.Hash  { return b.header.ParentHash }
 func (b *Block) TxHash() common.Hash      { return b.header.TxHash }

+ 1 - 1
core/types/block_test.go

@@ -47,7 +47,7 @@ func TestBlockEncoding(t *testing.T) {
 	check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
 	check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e"))
 	check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
-	check("Time", block.Time(), uint64(1426516743))
+	check("Time", block.Time(), big.NewInt(1426516743))
 	check("Size", block.Size(), common.StorageSize(len(blockEnc)))
 
 	tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)

+ 1 - 1
core/vm/environment.go

@@ -33,7 +33,7 @@ type Environment interface {
 	BlockNumber() *big.Int
 	GetHash(n uint64) common.Hash
 	Coinbase() common.Address
-	Time() uint64
+	Time() *big.Int
 	Difficulty() *big.Int
 	GasLimit() *big.Int
 	CanTransfer(from Account, balance *big.Int) bool

+ 1 - 1
core/vm/instructions.go

@@ -341,7 +341,7 @@ func opCoinbase(instr instruction, env Environment, context *Context, memory *Me
 }
 
 func opTimestamp(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {
-	stack.push(U256(new(big.Int).SetUint64(env.Time())))
+	stack.push(U256(new(big.Int).Set(env.Time())))
 }
 
 func opNumber(instr instruction, env Environment, context *Context, memory *Memory, stack *stack) {

+ 1 - 1
core/vm/jit_test.go

@@ -93,7 +93,7 @@ func (self *Env) StructLogs() []StructLog {
 
 //func (self *Env) PrevHash() []byte      { return self.parent }
 func (self *Env) Coinbase() common.Address { return common.Address{} }
-func (self *Env) Time() uint64             { return uint64(time.Now().Unix()) }
+func (self *Env) Time() *big.Int           { return big.NewInt(time.Now().Unix()) }
 func (self *Env) Difficulty() *big.Int     { return big.NewInt(0) }
 func (self *Env) State() *state.StateDB    { return nil }
 func (self *Env) GasLimit() *big.Int       { return self.gasLimit }

+ 1 - 1
core/vm/vm.go

@@ -491,7 +491,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
 		case TIMESTAMP:
 			time := self.env.Time()
 
-			stack.push(new(big.Int).SetUint64(time))
+			stack.push(new(big.Int).Set(time))
 
 		case NUMBER:
 			number := self.env.BlockNumber()

+ 1 - 1
core/vm_env.go

@@ -49,7 +49,7 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, header *type
 func (self *VMEnv) Origin() common.Address   { f, _ := self.msg.From(); return f }
 func (self *VMEnv) BlockNumber() *big.Int    { return self.header.Number }
 func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
-func (self *VMEnv) Time() uint64             { return self.header.Time }
+func (self *VMEnv) Time() *big.Int           { return self.header.Time }
 func (self *VMEnv) Difficulty() *big.Int     { return self.header.Difficulty }
 func (self *VMEnv) GasLimit() *big.Int       { return self.header.GasLimit }
 func (self *VMEnv) Value() *big.Int          { return self.msg.Value() }

+ 1 - 1
eth/handler.go

@@ -117,7 +117,7 @@ func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow po
 	manager.downloader = downloader.New(manager.eventMux, manager.chainman.HasBlock, manager.chainman.GetBlock, manager.chainman.CurrentBlock, manager.chainman.InsertChain, manager.removePeer)
 
 	validator := func(block *types.Block, parent *types.Block) error {
-		return core.ValidateHeader(pow, block.Header(), parent, true)
+		return core.ValidateHeader(pow, block.Header(), parent, true, false)
 	}
 	heighter := func() uint64 {
 		return manager.chainman.CurrentBlock().NumberU64()

+ 5 - 5
miner/worker.go

@@ -278,7 +278,7 @@ func (self *worker) wait() {
 					glog.V(logger.Error).Infoln("Invalid block found during mining")
 					continue
 				}
-				if err := core.ValidateHeader(self.eth.BlockProcessor().Pow, block.Header(), parent, true); err != nil && err != core.BlockFutureErr {
+				if err := core.ValidateHeader(self.eth.BlockProcessor().Pow, block.Header(), parent, true, false); err != nil && err != core.BlockFutureErr {
 					glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
 					continue
 				}
@@ -434,8 +434,8 @@ func (self *worker) commitNewWork() {
 	tstart := time.Now()
 	parent := self.chain.CurrentBlock()
 	tstamp := tstart.Unix()
-	if tstamp <= int64(parent.Time()) {
-		tstamp = int64(parent.Time()) + 1
+	if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) != 1 {
+		tstamp = parent.Time().Int64() + 1
 	}
 	// this will ensure we're not going off too far in the future
 	if now := time.Now().Unix(); tstamp > now+4 {
@@ -448,12 +448,12 @@ func (self *worker) commitNewWork() {
 	header := &types.Header{
 		ParentHash: parent.Hash(),
 		Number:     num.Add(num, common.Big1),
-		Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time(), parent.Number(), parent.Difficulty()),
+		Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time().Uint64(), parent.Number(), parent.Difficulty()),
 		GasLimit:   core.CalcGasLimit(parent),
 		GasUsed:    new(big.Int),
 		Coinbase:   self.coinbase,
 		Extra:      self.extra,
-		Time:       uint64(tstamp),
+		Time:       big.NewInt(tstamp),
 	}
 
 	previous := self.current

+ 7 - 0
tests/block_test.go

@@ -35,6 +35,13 @@ func TestBcUncleHeaderValidityTests(t *testing.T) {
 	}
 }
 
+func TestBcUncleTests(t *testing.T) {
+	err := RunBlockTest(filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func TestBcInvalidHeaderTests(t *testing.T) {
 	err := RunBlockTest(filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests)
 	if err != nil {

+ 3 - 3
tests/block_test_util.go

@@ -365,8 +365,8 @@ func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error {
 		return fmt.Errorf("GasUsed: expected: %v, decoded: %v", expectedGasUsed, h2.GasUsed)
 	}
 
-	expectedTimestamp := mustConvertUint(h.Timestamp, 16)
-	if expectedTimestamp != h2.Time {
+	expectedTimestamp := mustConvertBigInt(h.Timestamp, 16)
+	if expectedTimestamp.Cmp(h2.Time) != 0 {
 		return fmt.Errorf("Timestamp: expected: %v, decoded: %v", expectedTimestamp, h2.Time)
 	}
 
@@ -461,7 +461,7 @@ func mustConvertHeader(in btHeader) *types.Header {
 		GasUsed:     mustConvertBigInt(in.GasUsed, 16),
 		GasLimit:    mustConvertBigInt(in.GasLimit, 16),
 		Difficulty:  mustConvertBigInt(in.Difficulty, 16),
-		Time:        mustConvertUint(in.Timestamp, 16),
+		Time:        mustConvertBigInt(in.Timestamp, 16),
 		Nonce:       types.EncodeNonce(mustConvertUint(in.Nonce, 16)),
 	}
 	return header

File diff suppressed because it is too large
+ 76 - 0
tests/files/BlockchainTests/bcUncleTest.json


+ 3 - 3
tests/util.go

@@ -135,7 +135,7 @@ type Env struct {
 	coinbase common.Address
 
 	number     *big.Int
-	time       uint64
+	time       *big.Int
 	difficulty *big.Int
 	gasLimit   *big.Int
 
@@ -165,7 +165,7 @@ func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues
 	//env.parent = common.Hex2Bytes(envValues["previousHash"])
 	env.coinbase = common.HexToAddress(envValues["currentCoinbase"])
 	env.number = common.Big(envValues["currentNumber"])
-	env.time = common.Big(envValues["currentTimestamp"]).Uint64()
+	env.time = common.Big(envValues["currentTimestamp"])
 	env.difficulty = common.Big(envValues["currentDifficulty"])
 	env.gasLimit = common.Big(envValues["currentGasLimit"])
 	env.Gas = new(big.Int)
@@ -178,7 +178,7 @@ func (self *Env) BlockNumber() *big.Int  { return self.number }
 
 //func (self *Env) PrevHash() []byte      { return self.parent }
 func (self *Env) Coinbase() common.Address { return self.coinbase }
-func (self *Env) Time() uint64             { return self.time }
+func (self *Env) Time() *big.Int           { return self.time }
 func (self *Env) Difficulty() *big.Int     { return self.difficulty }
 func (self *Env) State() *state.StateDB    { return self.state }
 func (self *Env) GasLimit() *big.Int       { return self.gasLimit }

+ 2 - 1
xeth/types.go

@@ -19,6 +19,7 @@ package xeth
 import (
 	"bytes"
 	"fmt"
+	"math/big"
 	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -76,7 +77,7 @@ type Block struct {
 	Hash         string       `json:"hash"`
 	Transactions *common.List `json:"transactions"`
 	Uncles       *common.List `json:"uncles"`
-	Time         uint64       `json:"time"`
+	Time         *big.Int     `json:"time"`
 	Coinbase     string       `json:"coinbase"`
 	Name         string       `json:"name"`
 	GasLimit     string       `json:"gasLimit"`

Some files were not shown because too many files changed in this diff