chaingen

package
v0.0.0-...-82e7055 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2024 License: ISC Imports: 14 Imported by: 0

README

chaingen

ISC License [GoDoc] (http://godoc.org/github.com/james-ray/hcd/blockchain/chaingen)

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.

Examples

Installation

$ go get -u github.com/james-ray/hcd/blockchain/chaingen

License

Package chaingen is licensed under the copyfree ISC License.

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/james-ray/hcd/blockchain/chaingen"
	"github.com/james-ray/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)
	// below is the output
	// bp
	// bm0
	// bm1
	// bm2
	// bm3
	// bm4
	// bm5
	// bm6
	// bm7
	// bm8
	// bm9
	// bm10
	// bm11
	// bm12
	// bm13
	// bm14
	// bm15
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ReplaceBlockVersion

func ReplaceBlockVersion(newVersion int32) func(*wire.MsgBlock)

ReplaceBlockVersion returns a function that itself takes a block and modifies it by replacing the stake version of the header.

func ReplaceStakeVersion

func ReplaceStakeVersion(newVersion uint32) func(*wire.MsgBlock)

ReplaceStakeVersion returns a function that itself takes a block and modifies it by replacing the stake version of the header.

func ReplaceVoteVersions

func ReplaceVoteVersions(newVersion uint32) func(*wire.MsgBlock)

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

func ReplaceVotes(voteBits uint16, newVersion uint32) func(*wire.MsgBlock)

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

func MakeGenerator(params *chaincfg.Params) (Generator, error)

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

func (g *Generator) AssertBlockVersion(expected int32)

AssertBlockVersion panics if the current tip block associated with the generator does not have the specified version.

func (*Generator) AssertScriptSigOpsCount

func (g *Generator) AssertScriptSigOpsCount(script []byte, expected int)

AssertScriptSigOpsCount panics if the provided script does not have the specified number of signature operations.

func (*Generator) AssertStakeVersion

func (g *Generator) AssertStakeVersion(expected uint32)

AssertStakeVersion panics if the current tip block associated with the generator does not have the specified stake version in the header.

func (*Generator) AssertTipBlockHash

func (g *Generator) AssertTipBlockHash(expected chainhash.Hash)

AssertTipBlockHash panics if the current tip block associated with the generator does not match the specified hash.

func (*Generator) AssertTipBlockMerkleRoot

func (g *Generator) AssertTipBlockMerkleRoot(expected chainhash.Hash)

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

func (g *Generator) AssertTipBlockNumTxns(expected int)

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

func (g *Generator) AssertTipBlockSigOpsCount(expected int)

AssertTipBlockSigOpsCount panics if the current tip block associated with the generator does not have the specified number of signature operations.

func (*Generator) AssertTipBlockSize

func (g *Generator) AssertTipBlockSize(expected int)

AssertTipBlockSize panics if the if the current tip block associated with the generator does not have the specified size when serialized.

func (*Generator) AssertTipBlockTxOutOpReturn

func (g *Generator) AssertTipBlockTxOutOpReturn(txIndex, txOutIndex uint32)

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

func (g *Generator) AssertTipHeight(expected uint32)

AssertTipHeight panics if the current tip block associated with the generator does not have the specified height.

func (*Generator) BlockByHash

func (g *Generator) BlockByHash(hash *chainhash.Hash) *wire.MsgBlock

BlockByHash returns the block associated with the provided block hash. It will panic if the specified block hash does not exist.

func (*Generator) BlockByName

func (g *Generator) BlockByName(blockName string) *wire.MsgBlock

BlockByName returns the block associated with the provided block name. It will panic if the specified block name does not exist.

func (*Generator) CreateCoinbaseTx

func (g *Generator) CreateCoinbaseTx(blockHeight uint32, numVotes uint16) *wire.MsgTx

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

func (g *Generator) CreateSpendTx(spend *SpendableOut, fee hcutil.Amount) *wire.MsgTx

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

func (g *Generator) NumSpendableCoinbaseOuts() int

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) Params

func (g *Generator) Params() *chaincfg.Params

Params returns the chain params associated with the generator instance.

func (*Generator) ReplaceWithNVotes

func (g *Generator) ReplaceWithNVotes(numVotes uint16) func(*wire.MsgBlock)

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

func (g *Generator) SetTip(blockName string)

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) Tip

func (g *Generator) Tip() *wire.MsgBlock

Tip returns the current tip block of the generator instance.

func (*Generator) TipName

func (g *Generator) TipName() string

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL