Documentation ¶
Overview ¶
Package chaingen provides facilities for generating a full chain of blocks.
Overview ¶
Many consensus-related tests require a full chain of valid blocks with several pieces of contextual information such as versions and votes. Generating such a chain is not a trivial task due to things such as the fact that tickets must be purchased (at the correct ticket price), the appropriate winning votes must be cast (which implies keeping track of all live tickets and implementing the lottery selection algorithm), and all of the state-specific header fields such as the pool size and the proof-of-work and proof-of-stake difficulties must be set properly.
In order to simplify this complex process, this package provides a generator that keeps track of all of the necessary state and generates and solves blocks accordingly while allowing the caller to manipulate the blocks via munge functions.
Example (BasicUsage) ¶
This example demonstrates creating a new generator instance and using it to generate the required premine block and enough blocks to have mature coinbase outputs to work with along with asserting the generator state along the way.
package main import ( "fmt" "github.com/coolsnady/hcd/blockchain/chaingen" "github.com/coolsnady/hcd/chaincfg" ) func main() { params := &chaincfg.SimNetParams g, err := chaingen.MakeGenerator(params) if err != nil { fmt.Println(err) return } // Shorter versions of useful params for convenience. coinbaseMaturity := params.CoinbaseMaturity // --------------------------------------------------------------------- // Premine. // --------------------------------------------------------------------- // Add the required premine block. // // genesis -> bp g.CreatePremineBlock("bp", 0) g.AssertTipHeight(1) fmt.Println(g.TipName()) // --------------------------------------------------------------------- // Generate enough blocks to have mature coinbase outputs to work with. // // genesis -> bp -> bm0 -> bm1 -> ... -> bm# // --------------------------------------------------------------------- for i := uint16(0); i < coinbaseMaturity; i++ { blockName := fmt.Sprintf("bm%d", i) g.NextBlock(blockName, nil, nil) g.SaveTipCoinbaseOuts() fmt.Println(g.TipName()) } g.AssertTipHeight(uint32(coinbaseMaturity) + 1) }
Output: bp bm0 bm1 bm2 bm3 bm4 bm5 bm6 bm7 bm8 bm9 bm10 bm11 bm12 bm13 bm14 bm15
Index ¶
- func ReplaceBlockVersion(newVersion int32) func(*wire.MsgBlock)
- func ReplaceStakeVersion(newVersion uint32) func(*wire.MsgBlock)
- func ReplaceVoteVersions(newVersion uint32) func(*wire.MsgBlock)
- func ReplaceVotes(voteBits uint16, newVersion uint32) func(*wire.MsgBlock)
- func UniqueOpReturnScript() []byte
- type Generator
- func (g *Generator) AssertBlockVersion(expected int32)
- func (g *Generator) AssertScriptSigOpsCount(script []byte, expected int)
- func (g *Generator) AssertStakeVersion(expected uint32)
- func (g *Generator) AssertTipBlockHash(expected chainhash.Hash)
- func (g *Generator) AssertTipBlockMerkleRoot(expected chainhash.Hash)
- func (g *Generator) AssertTipBlockNumTxns(expected int)
- func (g *Generator) AssertTipBlockSigOpsCount(expected int)
- func (g *Generator) AssertTipBlockSize(expected int)
- func (g *Generator) AssertTipBlockTxOutOpReturn(txIndex, txOutIndex uint32)
- func (g *Generator) AssertTipHeight(expected uint32)
- func (g *Generator) BlockByHash(hash *chainhash.Hash) *wire.MsgBlock
- func (g *Generator) BlockByName(blockName string) *wire.MsgBlock
- func (g *Generator) CreateCoinbaseTx(blockHeight uint32, numVotes uint16) *wire.MsgTx
- func (g *Generator) CreatePremineBlock(blockName string, additionalAmount hcutil.Amount) *wire.MsgBlock
- func (g *Generator) CreateSpendTx(spend *SpendableOut, fee hcutil.Amount) *wire.MsgTx
- func (g *Generator) CreateSpendTxForTx(tx *wire.MsgTx, blockHeight, txIndex uint32, fee hcutil.Amount) *wire.MsgTx
- func (g *Generator) NextBlock(blockName string, spend *SpendableOut, ticketSpends []SpendableOut, ...) *wire.MsgBlock
- func (g *Generator) NumSpendableCoinbaseOuts() int
- func (g *Generator) OldestCoinbaseOuts() []SpendableOut
- func (g *Generator) Params() *chaincfg.Params
- func (g *Generator) ReplaceWithNVotes(numVotes uint16) func(*wire.MsgBlock)
- func (g *Generator) SaveSpendableCoinbaseOuts()
- func (g *Generator) SaveTipCoinbaseOuts()
- func (g *Generator) SetTip(blockName string)
- func (g *Generator) Tip() *wire.MsgBlock
- func (g *Generator) TipName() string
- func (g *Generator) UpdateBlockState(oldBlockName string, oldBlockHash chainhash.Hash, newBlockName string, ...)
- type SpendableOut
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ReplaceBlockVersion ¶
ReplaceBlockVersion returns a function that itself takes a block and modifies it by replacing the stake version of the header.
func ReplaceStakeVersion ¶
ReplaceStakeVersion returns a function that itself takes a block and modifies it by replacing the stake version of the header.
func ReplaceVoteVersions ¶
ReplaceVoteVersions returns a function that itself takes a block and modifies it by replacing the voter version of the stake transactions.
NOTE: This must only be used as a munger to the 'NextBlock' function or it will lead to an invalid live ticket pool.
func ReplaceVotes ¶
ReplaceVotes returns a function that itself takes a block and modifies it by replacing the voter version and bits of the stake transactions.
NOTE: This must only be used as a munger to the 'NextBlock' function or it will lead to an invalid live ticket pool.
func UniqueOpReturnScript ¶
func UniqueOpReturnScript() []byte
UniqueOpReturnScript returns a standard provably-pruneable OP_RETURN script with a random uint64 encoded as the data.
Types ¶
type Generator ¶
type Generator struct {
// contains filtered or unexported fields
}
Generator houses state used to ease the process of generating test blocks that build from one another along with housing other useful things such as available spendable outputs and generic payment scripts used throughout the tests.
func MakeGenerator ¶
MakeGenerator returns a generator instance initialized with the genesis block as the tip as well as a cached generic pay-to-script-hash script for OP_TRUE.
func (*Generator) AssertBlockVersion ¶
AssertBlockVersion panics if the current tip block associated with the generator does not have the specified version.
func (*Generator) AssertScriptSigOpsCount ¶
AssertScriptSigOpsCount panics if the provided script does not have the specified number of signature operations.
func (*Generator) AssertStakeVersion ¶
AssertStakeVersion panics if the current tip block associated with the generator does not have the specified stake version in the header.
func (*Generator) AssertTipBlockHash ¶
AssertTipBlockHash panics if the current tip block associated with the generator does not match the specified hash.
func (*Generator) AssertTipBlockMerkleRoot ¶
AssertTipBlockMerkleRoot panics if the merkle root in header of the current tip block associated with the generator does not match the specified hash.
func (*Generator) AssertTipBlockNumTxns ¶
AssertTipBlockNumTxns panics if the number of transactions in the current tip block associated with the generator does not match the specified value.
func (*Generator) AssertTipBlockSigOpsCount ¶
AssertTipBlockSigOpsCount panics if the current tip block associated with the generator does not have the specified number of signature operations.
func (*Generator) AssertTipBlockSize ¶
AssertTipBlockSize panics if the if the current tip block associated with the generator does not have the specified size when serialized.
func (*Generator) AssertTipBlockTxOutOpReturn ¶
AssertTipBlockTxOutOpReturn panics if the current tip block associated with the generator does not have an OP_RETURN script for the transaction output at the provided tx index and output index.
func (*Generator) AssertTipHeight ¶
AssertTipHeight panics if the current tip block associated with the generator does not have the specified height.
func (*Generator) BlockByHash ¶
BlockByHash returns the block associated with the provided block hash. It will panic if the specified block hash does not exist.
func (*Generator) BlockByName ¶
BlockByName returns the block associated with the provided block name. It will panic if the specified block name does not exist.
func (*Generator) CreateCoinbaseTx ¶
CreateCoinbaseTx returns a coinbase transaction paying an appropriate subsidy based on the passed block height and number of votes to the dev org and proof-of-work miner.
See the addCoinbaseTxOutputs documentation for a breakdown of the outputs the transaction contains.
func (*Generator) CreatePremineBlock ¶
func (g *Generator) CreatePremineBlock(blockName string, additionalAmount hcutil.Amount) *wire.MsgBlock
CreatePremineBlock generates the first block of the chain with the required premine payouts. The additional amount parameter can be used to create a block that is otherwise a completely valid premine block except it adds the extra amount to each payout and thus create a block that violates consensus.
func (*Generator) CreateSpendTx ¶
CreateSpendTx creates a transaction that spends from the provided spendable output and includes an additional unique OP_RETURN output to ensure the transaction ends up with a unique hash. The public key script is a simple OP_TRUE p2sh script which avoids the need to track addresses and signature scripts in the tests. The signature script is the opTrueRedeemScript.
func (*Generator) CreateSpendTxForTx ¶
func (g *Generator) CreateSpendTxForTx(tx *wire.MsgTx, blockHeight, txIndex uint32, fee hcutil.Amount) *wire.MsgTx
CreateSpendTxForTx creates a transaction that spends from the first output of the provided transaction and includes an additional unique OP_RETURN output to ensure the transaction ends up with a unique hash. The public key script is a simple OP_TRUE p2sh script which avoids the need to track addresses and signature scripts in the tests. This signature script the opTrueRedeemScript.
func (*Generator) NextBlock ¶
func (g *Generator) NextBlock(blockName string, spend *SpendableOut, ticketSpends []SpendableOut, mungers ...func(*wire.MsgBlock)) *wire.MsgBlock
NextBlock builds a new block that extends the current tip associated with the generator and updates the generator's tip to the newly generated block.
The block will include the following: - A coinbase with the following outputs:
- One that pays the required 10% subsidy to the dev org
- One that contains a standard coinbase OP_RETURN script
- Six that pay the required 60% subsidy to an OP_TRUE p2sh script
- When a spendable output is provided:
- A transaction that spends from the provided output the following outputs:
- One that pays the inputs amount minus 1 atom to an OP_TRUE p2sh script
- Once the coinbase maturity has been reached:
- A ticket purchase transaction (sstx) for each provided ticket spendable output with the following outputs:
- One OP_SSTX output that grants voting rights to an OP_TRUE p2sh script
- One OP_RETURN output that contains the required commitment and pays the subsidy to an OP_TRUE p2sh script
- One OP_SSTXCHANGE output that sends change to an OP_TRUE p2sh script
- Once the stake validation height has been reached:
- 5 vote transactions (ssgen) as required according to the live ticket pool and vote selection rules with the following outputs:
- One OP_RETURN followed by the block hash and height being voted on
- One OP_RETURN followed by the vote bits
- One or more OP_SSGEN outputs with the payouts according to the original ticket commitments
Additionally, if one or more munge functions are specified, they will be invoked with the block prior to solving it. This provides callers with the opportunity to modify the block which is especially useful for testing.
In order to simply the logic in the munge functions, the following rules are applied after all munge functions have been invoked: - The merkle root will be recalculated unless it was manually changed - The stake root will be recalculated unless it was manually changed - The size of the block will be recalculated unless it was manually changed - The block will be solved unless the nonce was changed
func (*Generator) NumSpendableCoinbaseOuts ¶
NumSpendableCoinbaseOuts returns the number of proof-of-work outputs that were previously saved to the generated but have not yet been collected.
func (*Generator) OldestCoinbaseOuts ¶
func (g *Generator) OldestCoinbaseOuts() []SpendableOut
OldestCoinbaseOuts removes the oldest set of coinbase proof-of-work outputs that was previously saved to the generator and returns the set as a slice.
func (*Generator) ReplaceWithNVotes ¶
ReplaceWithNVotes returns a function that itself takes a block and modifies it by replacing the votes in the stake tree with specified number of votes.
NOTE: This must only be used as a munger to the 'NextBlock' function or it will lead to an invalid live ticket pool. To help safeguard against improper usage, it will panic if called with a block that does not connect to the current tip block.
func (*Generator) SaveSpendableCoinbaseOuts ¶
func (g *Generator) SaveSpendableCoinbaseOuts()
SaveSpendableCoinbaseOuts adds all proof-of-work coinbase outputs starting from the block after the last block that had its coinbase outputs collected and ending at the current tip. This is useful to batch the collection of the outputs once the tests reach a stable point so they don't have to manually add them for the right tests which will ultimately end up being the best chain.
func (*Generator) SaveTipCoinbaseOuts ¶
func (g *Generator) SaveTipCoinbaseOuts()
SaveTipCoinbaseOuts adds the proof-of-work outputs of the coinbase tx in the current tip block to the list of spendable outputs.
func (*Generator) SetTip ¶
SetTip changes the tip of the instance to the block with the provided name. This is useful since the tip is used for things such as generating subsequent blocks.
func (*Generator) TipName ¶
TipName returns the name of the current tip block of the generator instance.
func (*Generator) UpdateBlockState ¶
func (g *Generator) UpdateBlockState(oldBlockName string, oldBlockHash chainhash.Hash, newBlockName string, newBlock *wire.MsgBlock)
UpdateBlockState manually updates the generator state to remove all internal map references to a block via its old hash and insert new ones for the new block hash. This is useful if the test code has to manually change a block after 'NextBlock' has returned.
type SpendableOut ¶
type SpendableOut struct {
// contains filtered or unexported fields
}
SpendableOut represents a transaction output that is spendable along with additional metadata such as the block its in and how much it pays.
func MakeSpendableOut ¶
func MakeSpendableOut(block *wire.MsgBlock, txIndex, txOutIndex uint32) SpendableOut
MakeSpendableOut returns a spendable output for the given block, transaction index within the block, and transaction output index within the transaction.
func MakeSpendableOutForTx ¶
func MakeSpendableOutForTx(tx *wire.MsgTx, blockHeight, txIndex, txOutIndex uint32) SpendableOut
MakeSpendableOutForTx returns a spendable output for the given transaction block height, transaction index within the block, and transaction output index within the transaction.
func (*SpendableOut) Amount ¶
func (s *SpendableOut) Amount() hcutil.Amount
Amount returns the amount associated with the spendable output.
func (*SpendableOut) BlockHeight ¶
func (s *SpendableOut) BlockHeight() uint32
BlockHeight returns the block height of the block the spendable output is in.
func (*SpendableOut) BlockIndex ¶
func (s *SpendableOut) BlockIndex() uint32
BlockIndex returns the offset into the block the spendable output is in.
func (*SpendableOut) PrevOut ¶
func (s *SpendableOut) PrevOut() wire.OutPoint
PrevOut returns the outpoint associated with the spendable output.