Merge pull request #6872 from filecoin-project/asr/block-height-fix
ValidateBlock: Assert that block header height's are greater than parents
This commit is contained in:
commit
26e961380a
@ -727,6 +727,11 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fast checks first
|
// fast checks first
|
||||||
|
|
||||||
|
if h.Height <= baseTs.Height() {
|
||||||
|
return xerrors.Errorf("block height not greater than parent height: %d != %d", h.Height, baseTs.Height())
|
||||||
|
}
|
||||||
|
|
||||||
nulls := h.Height - (baseTs.Height() + 1)
|
nulls := h.Height - (baseTs.Height() + 1)
|
||||||
if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
|
if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
|
||||||
return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs)
|
return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs)
|
||||||
|
@ -230,7 +230,7 @@ func (tu *syncTestUtil) pushTsExpectErr(to int, fts *store.FullTipSet, experr bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool, msgs [][]*types.SignedMessage, nulls abi.ChainEpoch) *store.FullTipSet {
|
func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool, msgs [][]*types.SignedMessage, nulls abi.ChainEpoch, push bool) *store.FullTipSet {
|
||||||
if miners == nil {
|
if miners == nil {
|
||||||
for i := range tu.g.Miners {
|
for i := range tu.g.Miners {
|
||||||
miners = append(miners, i)
|
miners = append(miners, i)
|
||||||
@ -247,7 +247,7 @@ func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int,
|
|||||||
var nts *store.FullTipSet
|
var nts *store.FullTipSet
|
||||||
var err error
|
var err error
|
||||||
if msgs != nil {
|
if msgs != nil {
|
||||||
nts, err = tu.g.NextTipSetFromMinersWithMessagesAndNulls(blk.TipSet(), maddrs, msgs, 0)
|
nts, err = tu.g.NextTipSetFromMinersWithMessagesAndNulls(blk.TipSet(), maddrs, msgs, nulls)
|
||||||
require.NoError(tu.t, err)
|
require.NoError(tu.t, err)
|
||||||
} else {
|
} else {
|
||||||
mt, err := tu.g.NextTipSetFromMiners(blk.TipSet(), maddrs, nulls)
|
mt, err := tu.g.NextTipSetFromMiners(blk.TipSet(), maddrs, nulls)
|
||||||
@ -255,17 +255,19 @@ func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int,
|
|||||||
nts = mt.TipSet
|
nts = mt.TipSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if push {
|
||||||
if fail {
|
if fail {
|
||||||
tu.pushTsExpectErr(to, nts, true)
|
tu.pushTsExpectErr(to, nts, true)
|
||||||
} else {
|
} else {
|
||||||
tu.pushFtsAndWait(to, nts, wait)
|
tu.pushFtsAndWait(to, nts, wait)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nts
|
return nts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tu *syncTestUtil) mineNewBlock(src int, miners []int) {
|
func (tu *syncTestUtil) mineNewBlock(src int, miners []int) {
|
||||||
mts := tu.mineOnBlock(tu.g.CurTipset, src, miners, true, false, nil, 0)
|
mts := tu.mineOnBlock(tu.g.CurTipset, src, miners, true, false, nil, 0, true)
|
||||||
tu.g.CurTipset = mts
|
tu.g.CurTipset = mts
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,7 +512,7 @@ func TestSyncBadTimestamp(t *testing.T) {
|
|||||||
fmt.Println("BASE: ", base.Cids())
|
fmt.Println("BASE: ", base.Cids())
|
||||||
tu.printHeads()
|
tu.printHeads()
|
||||||
|
|
||||||
a1 := tu.mineOnBlock(base, 0, nil, false, true, nil, 0)
|
a1 := tu.mineOnBlock(base, 0, nil, false, true, nil, 0, true)
|
||||||
|
|
||||||
tu.g.Timestamper = nil
|
tu.g.Timestamper = nil
|
||||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||||
@ -519,7 +521,7 @@ func TestSyncBadTimestamp(t *testing.T) {
|
|||||||
|
|
||||||
fmt.Println("After mine bad block!")
|
fmt.Println("After mine bad block!")
|
||||||
tu.printHeads()
|
tu.printHeads()
|
||||||
a2 := tu.mineOnBlock(base, 0, nil, true, false, nil, 0)
|
a2 := tu.mineOnBlock(base, 0, nil, true, false, nil, 0, true)
|
||||||
|
|
||||||
tu.waitUntilSync(0, client)
|
tu.waitUntilSync(0, client)
|
||||||
|
|
||||||
@ -563,7 +565,7 @@ func TestSyncBadWinningPoSt(t *testing.T) {
|
|||||||
tu.g.SetWinningPoStProver(tu.g.Miners[1], &badWpp{})
|
tu.g.SetWinningPoStProver(tu.g.Miners[1], &badWpp{})
|
||||||
|
|
||||||
// now ensure that new blocks are not accepted
|
// now ensure that new blocks are not accepted
|
||||||
tu.mineOnBlock(base, client, nil, false, true, nil, 0)
|
tu.mineOnBlock(base, client, nil, false, true, nil, 0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tu *syncTestUtil) loadChainToNode(to int) {
|
func (tu *syncTestUtil) loadChainToNode(to int) {
|
||||||
@ -613,16 +615,16 @@ func TestSyncFork(t *testing.T) {
|
|||||||
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
||||||
|
|
||||||
// The two nodes fork at this point into 'a' and 'b'
|
// The two nodes fork at this point into 'a' and 'b'
|
||||||
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0)
|
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0, true)
|
||||||
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0)
|
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0, true)
|
||||||
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0)
|
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0, true)
|
||||||
|
|
||||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||||
// chain B will now be heaviest
|
// chain B will now be heaviest
|
||||||
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0)
|
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
|
|
||||||
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
||||||
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
||||||
@ -686,13 +688,13 @@ func TestDuplicateNonce(t *testing.T) {
|
|||||||
msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])}
|
msgs[k] = []*types.SignedMessage{makeMsg(tu.g.Miners[k])}
|
||||||
}
|
}
|
||||||
|
|
||||||
ts1 := tu.mineOnBlock(base, 0, []int{0, 1}, true, false, msgs, 0)
|
ts1 := tu.mineOnBlock(base, 0, []int{0, 1}, true, false, msgs, 0, true)
|
||||||
|
|
||||||
tu.waitUntilSyncTarget(0, ts1.TipSet())
|
tu.waitUntilSyncTarget(0, ts1.TipSet())
|
||||||
|
|
||||||
// mine another tipset
|
// mine another tipset
|
||||||
|
|
||||||
ts2 := tu.mineOnBlock(ts1, 0, []int{0, 1}, true, false, make([][]*types.SignedMessage, 2), 0)
|
ts2 := tu.mineOnBlock(ts1, 0, []int{0, 1}, true, false, make([][]*types.SignedMessage, 2), 0, true)
|
||||||
tu.waitUntilSyncTarget(0, ts2.TipSet())
|
tu.waitUntilSyncTarget(0, ts2.TipSet())
|
||||||
|
|
||||||
var includedMsg cid.Cid
|
var includedMsg cid.Cid
|
||||||
@ -778,7 +780,7 @@ func TestBadNonce(t *testing.T) {
|
|||||||
msgs := make([][]*types.SignedMessage, 1)
|
msgs := make([][]*types.SignedMessage, 1)
|
||||||
msgs[0] = []*types.SignedMessage{makeBadMsg()}
|
msgs[0] = []*types.SignedMessage{makeBadMsg()}
|
||||||
|
|
||||||
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0)
|
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test introduces a block that has 2 messages, with the same sender, and same nonce.
|
// This test introduces a block that has 2 messages, with the same sender, and same nonce.
|
||||||
@ -832,7 +834,7 @@ func TestMismatchedNoncesRobustID(t *testing.T) {
|
|||||||
msgs := make([][]*types.SignedMessage, 1)
|
msgs := make([][]*types.SignedMessage, 1)
|
||||||
msgs[0] = []*types.SignedMessage{makeMsg(false), makeMsg(true)}
|
msgs[0] = []*types.SignedMessage{makeMsg(false), makeMsg(true)}
|
||||||
|
|
||||||
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0)
|
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs, 0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test introduces a block that has 2 messages, with the same sender, and nonces N and N+1 (so both can be included in a block)
|
// This test introduces a block that has 2 messages, with the same sender, and nonces N and N+1 (so both can be included in a block)
|
||||||
@ -886,7 +888,7 @@ func TestMatchedNoncesRobustID(t *testing.T) {
|
|||||||
msgs := make([][]*types.SignedMessage, 1)
|
msgs := make([][]*types.SignedMessage, 1)
|
||||||
msgs[0] = []*types.SignedMessage{makeMsg(ba.Nonce, false), makeMsg(ba.Nonce+1, true)}
|
msgs[0] = []*types.SignedMessage{makeMsg(ba.Nonce, false), makeMsg(ba.Nonce+1, true)}
|
||||||
|
|
||||||
tu.mineOnBlock(base, 0, []int{0}, true, false, msgs, 0)
|
tu.mineOnBlock(base, 0, []int{0}, true, false, msgs, 0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkSyncBasic(b *testing.B) {
|
func BenchmarkSyncBasic(b *testing.B) {
|
||||||
@ -951,19 +953,19 @@ func TestSyncCheckpointHead(t *testing.T) {
|
|||||||
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
||||||
|
|
||||||
// The two nodes fork at this point into 'a' and 'b'
|
// The two nodes fork at this point into 'a' and 'b'
|
||||||
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0)
|
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0, true)
|
||||||
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0)
|
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0, true)
|
||||||
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0)
|
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0, true)
|
||||||
|
|
||||||
tu.waitUntilSyncTarget(p1, a.TipSet())
|
tu.waitUntilSyncTarget(p1, a.TipSet())
|
||||||
tu.checkpointTs(p1, a.TipSet().Key())
|
tu.checkpointTs(p1, a.TipSet().Key())
|
||||||
|
|
||||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||||
// chain B will now be heaviest
|
// chain B will now be heaviest
|
||||||
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0)
|
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
|
|
||||||
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
||||||
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
||||||
@ -998,19 +1000,19 @@ func TestSyncCheckpointEarlierThanHead(t *testing.T) {
|
|||||||
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height())
|
||||||
|
|
||||||
// The two nodes fork at this point into 'a' and 'b'
|
// The two nodes fork at this point into 'a' and 'b'
|
||||||
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0)
|
a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil, 0, true)
|
||||||
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0)
|
a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil, 0, true)
|
||||||
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0)
|
a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil, 0, true)
|
||||||
|
|
||||||
tu.waitUntilSyncTarget(p1, a.TipSet())
|
tu.waitUntilSyncTarget(p1, a.TipSet())
|
||||||
tu.checkpointTs(p1, a1.TipSet().Key())
|
tu.checkpointTs(p1, a1.TipSet().Key())
|
||||||
|
|
||||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||||
// chain B will now be heaviest
|
// chain B will now be heaviest
|
||||||
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0)
|
b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0)
|
b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil, 0, true)
|
||||||
|
|
||||||
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
fmt.Println("A: ", a.Cids(), a.TipSet().Height())
|
||||||
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
fmt.Println("B: ", b.Cids(), b.TipSet().Height())
|
||||||
@ -1048,7 +1050,7 @@ func TestDrandNull(t *testing.T) {
|
|||||||
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
|
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
|
||||||
|
|
||||||
beforeNull := tu.g.CurTipset
|
beforeNull := tu.g.CurTipset
|
||||||
afterNull := tu.mineOnBlock(beforeNull, p0, nil, false, false, nil, 2)
|
afterNull := tu.mineOnBlock(beforeNull, p0, nil, false, false, nil, 2, true)
|
||||||
nullHeight := beforeNull.TipSet().Height() + 1
|
nullHeight := beforeNull.TipSet().Height() + 1
|
||||||
if afterNull.TipSet().Height() == nullHeight {
|
if afterNull.TipSet().Height() == nullHeight {
|
||||||
t.Fatal("didn't inject nulls as expected")
|
t.Fatal("didn't inject nulls as expected")
|
||||||
@ -1065,14 +1067,14 @@ func TestDrandNull(t *testing.T) {
|
|||||||
require.Equal(t, []byte(rand), expectedRand)
|
require.Equal(t, []byte(rand), expectedRand)
|
||||||
|
|
||||||
// zoom zoom to past the v5 upgrade by injecting many many nulls
|
// zoom zoom to past the v5 upgrade by injecting many many nulls
|
||||||
postUpgrade := tu.mineOnBlock(afterNull, p0, nil, false, false, nil, v5h)
|
postUpgrade := tu.mineOnBlock(afterNull, p0, nil, false, false, nil, v5h, true)
|
||||||
nv, err := tu.nds[p0].StateNetworkVersion(tu.ctx, postUpgrade.TipSet().Key())
|
nv, err := tu.nds[p0].StateNetworkVersion(tu.ctx, postUpgrade.TipSet().Key())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
if nv != network.Version13 {
|
if nv != network.Version13 {
|
||||||
t.Fatal("expect to be v13 by now")
|
t.Fatal("expect to be v13 by now")
|
||||||
}
|
}
|
||||||
|
|
||||||
afterNull = tu.mineOnBlock(postUpgrade, p0, nil, false, false, nil, 2)
|
afterNull = tu.mineOnBlock(postUpgrade, p0, nil, false, false, nil, 2, true)
|
||||||
nullHeight = postUpgrade.TipSet().Height() + 1
|
nullHeight = postUpgrade.TipSet().Height() + 1
|
||||||
if afterNull.TipSet().Height() == nullHeight {
|
if afterNull.TipSet().Height() == nullHeight {
|
||||||
t.Fatal("didn't inject nulls as expected")
|
t.Fatal("didn't inject nulls as expected")
|
||||||
@ -1104,3 +1106,22 @@ func TestDrandNull(t *testing.T) {
|
|||||||
|
|
||||||
build.UpgradeHyperdriveHeight = ov5h
|
build.UpgradeHyperdriveHeight = ov5h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInvalidHeight(t *testing.T) {
|
||||||
|
H := 50
|
||||||
|
tu := prepSyncTest(t, H)
|
||||||
|
|
||||||
|
client := tu.addClientNode()
|
||||||
|
|
||||||
|
require.NoError(t, tu.mn.LinkAll())
|
||||||
|
tu.connect(client, 0)
|
||||||
|
tu.waitUntilSync(0, client)
|
||||||
|
|
||||||
|
base := tu.g.CurTipset
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
base = tu.mineOnBlock(base, 0, nil, false, false, nil, 0, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
tu.mineOnBlock(base, 0, nil, false, true, nil, -1, true)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user