From 7324176f702a77fc331bf16a968d2eb4bccce021 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Mon, 24 Aug 2015 02:52:53 +0200 Subject: Add tests for uncle timestamps and refactor timestamp type --- core/block_processor.go | 20 +++++++++++++------- core/block_processor_test.go | 4 ++-- core/chain_makers.go | 11 ++++++++--- core/chain_manager.go | 3 ++- core/error.go | 7 ++++--- core/genesis.go | 2 +- core/types/block.go | 9 ++++++--- core/types/block_test.go | 2 +- core/vm/environment.go | 2 +- core/vm/instructions.go | 2 +- core/vm/jit_test.go | 2 +- core/vm/vm.go | 2 +- core/vm_env.go | 2 +- 13 files changed, 42 insertions(+), 26 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index dd7fe8962..99d27fa71 100644 --- a/core/block_processor.go +++ b/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) } diff --git a/core/block_processor_test.go b/core/block_processor_test.go index 4525f417b..e0b2d3313 100644 --- a/core/block_processor_test.go +++ b/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") } diff --git a/core/chain_makers.go b/core/chain_makers.go index 0bb1df95a..b009e0c28 100644 --- a/core/chain_makers.go +++ b/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, } } diff --git a/core/chain_manager.go b/core/chain_manager.go index cf5b8bd78..c8127951e 100644 --- a/core/chain_manager.go +++ b/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) } diff --git a/core/error.go b/core/error.go index 5e6ff4de7..09eea22d6 100644 --- a/core/error.go +++ b/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 diff --git a/core/genesis.go b/core/genesis.go index 97afb3a4a..7d4e03c99 100644 --- a/core/genesis.go +++ b/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), diff --git a/core/types/block.go b/core/types/block.go index 427a3e6cb..2188e6d4d 100644 --- a/core/types/block.go +++ b/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 } diff --git a/core/types/block_test.go b/core/types/block_test.go index aebb6328b..cdd8431f4 100644 --- a/core/types/block_test.go +++ b/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) diff --git a/core/vm/environment.go b/core/vm/environment.go index 5a1bf3201..916081f51 100644 --- a/core/vm/environment.go +++ b/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 diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2de35a443..aa0117cc8 100644 --- a/core/vm/instructions.go +++ b/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) { diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go index b9e2c6999..d8e442637 100644 --- a/core/vm/jit_test.go +++ b/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 } diff --git a/core/vm/vm.go b/core/vm/vm.go index da764004a..d9e1a0ce5 100644 --- a/core/vm/vm.go +++ b/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() diff --git a/core/vm_env.go b/core/vm_env.go index 719829543..a08f024fe 100644 --- a/core/vm_env.go +++ b/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() } -- cgit