Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: Implement reject new script and tx vers. #2716

Merged
merged 5 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion blockchain/agendas_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2017-2020 The Decred developers
// Copyright (c) 2017-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -695,3 +695,120 @@ func TestTreasuryFeaturesDeployment(t *testing.T) {
testTreasuryFeaturesDeployment(t, chaincfg.TestNet3Params())
testTreasuryFeaturesDeployment(t, chaincfg.RegNetParams())
}

// testExplicitVerUpgradesDeployment ensures the deployment of the explcit
// version upgrades agenda activates for the provided network parameters.
func testExplicitVerUpgradesDeployment(t *testing.T, params *chaincfg.Params) {
// Clone the parameters so they can be mutated, find the correct deployment
// for the header commitments agenda as well as the yes vote choice within
// it, and, finally, ensure it is always available to vote by removing the
// time constraints to prevent test failures when the real expiration time
// passes.
params = cloneParams(params)
deploymentVer, deployment, err := findDeployment(params,
chaincfg.VoteIDExplicitVersionUpgrades)
if err != nil {
t.Fatal(err)
}
yesChoice, err := findDeploymentChoice(deployment, "yes")
if err != nil {
t.Fatal(err)
}
removeDeploymentTimeConstraints(deployment)

// Shorter versions of params for convenience.
stakeValidationHeight := uint32(params.StakeValidationHeight)
ruleChangeActivationInterval := params.RuleChangeActivationInterval

tests := []struct {
name string
numNodes uint32 // num fake nodes to create
curActive bool // whether agenda active for current block
nextActive bool // whether agenda active for NEXT block
}{{
name: "stake validation height",
numNodes: stakeValidationHeight,
curActive: false,
nextActive: false,
}, {
name: "started",
numNodes: ruleChangeActivationInterval,
curActive: false,
nextActive: false,
}, {
name: "lockedin",
numNodes: ruleChangeActivationInterval,
curActive: false,
nextActive: false,
}, {
name: "one before active",
numNodes: ruleChangeActivationInterval - 1,
curActive: false,
nextActive: true,
}, {
name: "exactly active",
numNodes: 1,
curActive: true,
nextActive: true,
}, {
name: "one after active",
numNodes: 1,
curActive: true,
nextActive: true,
}}

curTimestamp := time.Now()
bc := newFakeChain(params)
node := bc.bestChain.Tip()
for _, test := range tests {
for i := uint32(0); i < test.numNodes; i++ {
node = newFakeNode(node, int32(deploymentVer), deploymentVer, 0,
curTimestamp)

// Create fake votes that vote yes on the agenda to ensure it is
// activated.
for j := uint16(0); j < params.TicketsPerBlock; j++ {
node.votes = append(node.votes, stake.VoteVersionTuple{
Version: deploymentVer,
Bits: yesChoice.Bits | 0x01,
})
}
bc.index.AddNode(node)
bc.bestChain.SetTip(node)
curTimestamp = curTimestamp.Add(time.Second)
}

// Ensure the agenda reports the expected activation status for the
// current block.
gotActive, err := bc.isExplicitVerUpgradesAgendaActive(node.parent)
if err != nil {
t.Errorf("%s: unexpected err: %v", test.name, err)
continue
}
if gotActive != test.curActive {
t.Errorf("%s: mismatched current active status - got: %v, want: %v",
test.name, gotActive, test.curActive)
continue
}

// Ensure the agenda reports the expected activation status for the NEXT
// block
gotActive, err = bc.IsExplicitVerUpgradesAgendaActive(&node.hash)
if err != nil {
t.Errorf("%s: unexpected err: %v", test.name, err)
continue
}
if gotActive != test.nextActive {
t.Errorf("%s: mismatched next active status - got: %v, want: %v",
test.name, gotActive, test.nextActive)
continue
}
}
}

// TestExplictVerUpgradesDeployment ensures the deployment of the explicit
// version upgrades agenda activates as expected.
func TestExplictVerUpgradesDeployment(t *testing.T) {
testExplicitVerUpgradesDeployment(t, chaincfg.MainNetParams())
testExplicitVerUpgradesDeployment(t, chaincfg.RegNetParams())
}
24 changes: 8 additions & 16 deletions blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,17 +553,13 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block,
node.height, prevHash, tip.hash, tip.height)
}

isTreasuryEnabled, err := b.isTreasuryAgendaActive(node.parent)
if err != nil {
return err
}

// Create agenda flags for checking transactions based on which ones are
// active as of the block being connected.
checkTxFlags := AFNone
if isTreasuryEnabled {
checkTxFlags |= AFTreasuryEnabled
checkTxFlags, err := b.determineCheckTxFlags(node.parent)
if err != nil {
return err
}
isTreasuryEnabled := checkTxFlags.IsTreasuryEnabled()

// Sanity check the correct number of stxos are provided.
if len(stxos) != countSpentOutputs(block, isTreasuryEnabled) {
Expand Down Expand Up @@ -781,17 +777,13 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block, parent *dcrutil.Blo
tip.height)
}

isTreasuryEnabled, err := b.isTreasuryAgendaActive(node.parent)
if err != nil {
return err
}

// Create agenda flags for checking transactions based on which ones were
// active as of the block being disconnected.
checkTxFlags := AFNone
if isTreasuryEnabled {
checkTxFlags |= AFTreasuryEnabled
checkTxFlags, err := b.determineCheckTxFlags(node.parent)
if err != nil {
return err
}
isTreasuryEnabled := checkTxFlags.IsTreasuryEnabled()

// Write any modified block index entries to the database before
// updating the best state.
Expand Down
10 changes: 9 additions & 1 deletion blockchain/error.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -143,11 +143,19 @@ const (
// input more than once.
ErrDuplicateTxInputs = ErrorKind("ErrDuplicateTxInputs")

// ErrTxVersionTooHigh indicates a transaction version is higher than the
// maximum version allowed by the active consensus rules.
ErrTxVersionTooHigh = ErrorKind("ErrTxVersionTooHigh")

// ErrBadTxInput indicates a transaction input is invalid in some way
// such as referencing a previous transaction outpoint which is out of
// range or not referencing one at all.
ErrBadTxInput = ErrorKind("ErrBadTxInput")

// ErrScriptVersionTooHigh indicates a transaction script version is higher
// than the maximum version allowed by the active consensus rules.
ErrScriptVersionTooHigh = ErrorKind("ErrScriptVersionTooHigh")

// ErrMissingTxOut indicates a transaction output referenced by an input
// either does not exist or has already been spent.
ErrMissingTxOut = ErrorKind("ErrMissingTxOut")
Expand Down
4 changes: 3 additions & 1 deletion blockchain/error_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2014 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -43,7 +43,9 @@ func TestErrorKindStringer(t *testing.T) {
{ErrTxTooBig, "ErrTxTooBig"},
{ErrBadTxOutValue, "ErrBadTxOutValue"},
{ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
{ErrTxVersionTooHigh, "ErrTxVersionTooHigh"},
{ErrBadTxInput, "ErrBadTxInput"},
{ErrScriptVersionTooHigh, "ErrScriptVersionTooHigh"},
{ErrMissingTxOut, "ErrMissingTxOut"},
{ErrUnfinalizedTx, "ErrUnfinalizedTx"},
{ErrDuplicateTx, "ErrDuplicateTx"},
Expand Down
52 changes: 51 additions & 1 deletion blockchain/thresholdstate.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2017-2020 The Decred developers
// Copyright (c) 2017-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -778,6 +778,56 @@ func (b *BlockChain) IsRevertTreasuryPolicyActive(prevHash *chainhash.Hash) (boo
return isActive, err
}

// isExplicitVerUpgradesAgendaActive returns whether or not the explicit version
// upgrades agenda, as defined in DCP0008, has passed and is now active from the
// point of view of the passed block node.
//
// It is important to note that, as the variable name indicates, this function
// expects the block node prior to the block for which the deployment state is
// desired. In other words, the returned deployment state is for the block
// AFTER the passed node.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) isExplicitVerUpgradesAgendaActive(prevNode *blockNode) (bool, error) {
const deploymentID = chaincfg.VoteIDExplicitVersionUpgrades
deploymentVer, ok := b.deploymentVers[deploymentID]
if !ok {
return true, nil
}

state, err := b.deploymentState(prevNode, deploymentVer, deploymentID)
if err != nil {
return false, err
}

// NOTE: The choice field of the return threshold state is not examined
// here because there is only one possible choice that can be active for
// the agenda, which is yes, so there is no need to check it.
return state.State == ThresholdActive, nil
}

// IsExplicitVerUpgradesAgendaActive returns whether or not the explicit version
// upgrades agenda, as defined in DCP0008, has passed and is now active for the
// block AFTER the given block.
//
// This function is safe for concurrent access.
func (b *BlockChain) IsExplicitVerUpgradesAgendaActive(prevHash *chainhash.Hash) (bool, error) {
// The agenda is never active for the genesis block.
if *prevHash == *zeroHash {
return false, nil
}

prevNode := b.index.LookupNode(prevHash)
if prevNode == nil || !b.index.CanValidate(prevNode) {
return false, unknownBlockError(prevHash)
}

b.chainLock.Lock()
isActive, err := b.isExplicitVerUpgradesAgendaActive(prevNode)
b.chainLock.Unlock()
return isActive, err
}

// VoteCounts is a compacted struct that is used to message vote counts.
type VoteCounts struct {
Total uint32
Expand Down
Loading