From 695c0e5a68c42a81b49eda5e2153561e2e2dfa20 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 14 Oct 2018 15:33:36 +0300 Subject: [PATCH] [DEV-206] allow block timestamp to be equal to past median time (#89) * [DEV-206] allow block timestamp to be equal to past median time * [DEV-206] make more specific error messages * [DEV-206] make independent nodes in TestPastMedianTime --- blockdag/validate.go | 4 +-- blockdag/validate_test.go | 66 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/blockdag/validate.go b/blockdag/validate.go index 8cac2ac2c..5452dd261 100644 --- a/blockdag/validate.go +++ b/blockdag/validate.go @@ -642,10 +642,10 @@ func (dag *BlockDAG) checkBlockHeaderContext(header *wire.BlockHeader, bluestPar return ruleError(ErrUnexpectedDifficulty, str) } - // Ensure the timestamp for the block header is after the + // Ensure the timestamp for the block header is not before the // median time of the last several blocks (medianTimeBlocks). medianTime := bluestParent.CalcPastMedianTime() - if !header.Timestamp.After(medianTime) { + if header.Timestamp.Before(medianTime) { str := "block timestamp of %v is not after expected %v" str = fmt.Sprintf(str, header.Timestamp, medianTime) return ruleError(ErrTimeTooOld, str) diff --git a/blockdag/validate_test.go b/blockdag/validate_test.go index 271eb258b..5f66dd8af 100644 --- a/blockdag/validate_test.go +++ b/blockdag/validate_test.go @@ -501,9 +501,71 @@ func TestCheckSerializedHeight(t *testing.T) { } } +func TestPastMedianTime(t *testing.T) { + dag := newTestDAG(&dagconfig.MainNetParams) + tip := dag.genesis + blockVersion := int32(0x10000000) + + blockTime := tip.Header().Timestamp + + for i := 0; i < 100; i++ { + blockTime = blockTime.Add(time.Second) + tip = newTestNode(setFromSlice(tip), + blockVersion, + 0, + blockTime, + dagconfig.MainNetParams.K) + } + + // Checks that a block is valid if it has timestamp equals to past median time + height := tip.height + 1 + node := newTestNode(setFromSlice(tip), + blockVersion, + 0, + tip.CalcPastMedianTime(), + dagconfig.MainNetParams.K) + + header := node.Header() + err := dag.checkBlockHeaderContext(&header, node.parents.bluest(), height, BFNone) + if err != nil { + t.Errorf("TestPastMedianTime: unexpected error from checkBlockHeaderContext: %v"+ + "(a block with timestamp equals to past median time should be valid)", err) + } + + // Checks that a block is valid if its timestamp is after past median time + height = tip.height + 1 + node = newTestNode(setFromSlice(tip), + blockVersion, + 0, + tip.CalcPastMedianTime().Add(time.Second), + dagconfig.MainNetParams.K) + + header = node.Header() + err = dag.checkBlockHeaderContext(&header, node.parents.bluest(), height, BFNone) + if err != nil { + t.Errorf("TestPastMedianTime: unexpected error from checkBlockHeaderContext: %v"+ + "(a block with timestamp bigger than past median time should be valid)", err) + } + + // Checks that a block is invalid if its timestamp is before past median time + height = tip.height + 1 + node = newTestNode(setFromSlice(tip), + blockVersion, + 0, + tip.CalcPastMedianTime().Add(-time.Second), + dagconfig.MainNetParams.K) + + header = node.Header() + err = dag.checkBlockHeaderContext(&header, node.parents.bluest(), height, BFNone) + if err == nil { + t.Errorf("TestPastMedianTime: unexpected success: block should be invalid if its timestamp is before past median time") + } + +} + func TestValidateParents(t *testing.T) { - blockDAG := newTestDAG(&dagconfig.MainNetParams) - genesisNode := blockDAG.genesis + dag := newTestDAG(&dagconfig.MainNetParams) + genesisNode := dag.genesis blockVersion := int32(0x10000000) blockTime := genesisNode.Header().Timestamp