From 2d6a9bbb1828ff5d050a8a487fc1d87e5789209d Mon Sep 17 00:00:00 2001 From: Derek Leung Date: Wed, 18 Dec 2019 17:41:18 -0500 Subject: [PATCH] Support variable-delay protocol upgrades in ConsensusFuture. Also add some unit tests for variable-delay protocol upgrades. --- config/config.go | 2 ++ data/bookkeeping/block_test.go | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/config/config.go b/config/config.go index d20f8d8f80..0047d54dfb 100644 --- a/config/config.go +++ b/config/config.go @@ -480,6 +480,8 @@ func initConsensusProtocols() { // but not yet released in a production protocol version. vFuture := v20 vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{} + vFuture.MinUpgradeWaitRounds = 10000 + vFuture.MaxUpgradeWaitRounds = 150000 Consensus[protocol.ConsensusFuture] = vFuture } diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index 6fe6ed839b..c3e68a6112 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -35,6 +35,7 @@ var proto1 = protocol.ConsensusVersion("Test1") var proto2 = protocol.ConsensusVersion("Test2") var proto3 = protocol.ConsensusVersion("Test3") var protoUnsupported = protocol.ConsensusVersion("TestUnsupported") +var protoDelay = protocol.ConsensusVersion("TestDelay") func init() { params1 := config.Consensus[protocol.ConsensusCurrentVersion] @@ -46,6 +47,14 @@ func init() { params2 := config.Consensus[protocol.ConsensusCurrentVersion] params2.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{} config.Consensus[proto2] = params2 + + paramsDelay := config.Consensus[protocol.ConsensusCurrentVersion] + paramsDelay.MinUpgradeWaitRounds = 3 + paramsDelay.MaxUpgradeWaitRounds = 7 + paramsDelay.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{ + proto1: 5, + } + config.Consensus[protoDelay] = paramsDelay } func TestUpgradeVote(t *testing.T) { @@ -109,6 +118,30 @@ func TestUpgradeVote(t *testing.T) { require.Equal(t, s1.NextProtocolSwitchOn, basics.Round(0)) } +func TestUpgradeVariableDelay(t *testing.T) { + s := UpgradeState{ + CurrentProtocol: protoDelay, + } + + _, err := s.applyUpgradeVote(basics.Round(10), UpgradeVote{UpgradePropose: proto1, UpgradeDelay: 2}) + require.Error(t, err, "accepted upgrade vote with delay less than MinUpgradeWaitRounds") + + _, err = s.applyUpgradeVote(basics.Round(10), UpgradeVote{UpgradePropose: proto1, UpgradeDelay: 8}) + require.Error(t, err, "accepted upgrade vote with delay more than MaxUpgradeWaitRounds") + + _, err = s.applyUpgradeVote(basics.Round(10), UpgradeVote{UpgradePropose: proto1, UpgradeDelay: 5}) + require.NoError(t, err, "did not accept upgrade vote with in-bounds delay") + + _, err = s.applyUpgradeVote(basics.Round(10), UpgradeVote{UpgradePropose: proto1, UpgradeDelay: 3}) + require.NoError(t, err, "did not accept upgrade vote with minimal delay") + + _, err = s.applyUpgradeVote(basics.Round(10), UpgradeVote{UpgradePropose: proto1, UpgradeDelay: 7}) + require.NoError(t, err, "did not accept upgrade vote with maximal delay") + + _, err = s.applyUpgradeVote(basics.Round(10), UpgradeVote{UpgradePropose: proto1, UpgradeDelay: 0}) + require.Error(t, err, "accepted upgrade vote with zero (below minimal) delay") +} + func TestMakeBlockUpgrades(t *testing.T) { var b Block b.BlockHeader.GenesisID = t.Name() @@ -133,6 +166,30 @@ func TestMakeBlockUpgrades(t *testing.T) { require.NoError(t, err) require.Equal(t, b3.UpgradePropose, protocol.ConsensusVersion("")) require.Equal(t, b3.UpgradeApprove, false) + + var bd Block + bd.BlockHeader.GenesisID = t.Name() + bd.CurrentProtocol = protoDelay + bd.BlockHeader.GenesisID = "test" + crypto.RandBytes(bd.BlockHeader.GenesisHash[:]) + + bd1 := MakeBlock(bd.BlockHeader) + err = bd1.PreCheck(bd.BlockHeader) + require.NoError(t, err) + require.Equal(t, bd1.UpgradePropose, proto1) + require.Equal(t, bd1.UpgradeApprove, true) + require.Equal(t, bd1.UpgradeDelay, basics.Round(5)) + require.Equal(t, bd1.NextProtocol, proto1) + require.Equal(t, bd1.NextProtocolSwitchOn-bd1.NextProtocolVoteBefore, basics.Round(5)) + + bd2 := MakeBlock(bd1.BlockHeader) + err = bd2.PreCheck(bd1.BlockHeader) + require.NoError(t, err) + require.Equal(t, bd2.UpgradePropose, protocol.ConsensusVersion("")) + require.Equal(t, bd2.UpgradeApprove, true) + require.Equal(t, bd2.UpgradeDelay, basics.Round(0)) + require.Equal(t, bd2.NextProtocol, proto1) + require.Equal(t, bd2.NextProtocolSwitchOn-bd2.NextProtocolVoteBefore, basics.Round(5)) } func TestBlockUnsupported(t *testing.T) {