ledger

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Nov 24, 2019 License: AGPL-3.0 Imports: 28 Imported by: 0

README

Ledger

The ledger represents the state of an Algorand node. The core state of the ledger is a sequence of blocks (the blockchain). The ledger also maintains several trackers: state machines that consume the blockchain as input. One example of a tracker is the account state tracker, which keeps track of the state of individual accounts (balance, status, etc).

The external API for the ledger (for use by callers outside of this package) is defined in ledger.go.

Blocks

The ledger exposes the following functions for managing the blocks:

  • AddBlock(block, cert) adds a new block to the ledger, along with a certificate for that block. The ledger does not check the certificate's validity. If the block is not from the correct round (i.e., latest known plus one), an error is returned. The block is added to an in-memory queue of pending blocks, and is flushed to disk in the background for performance.

  • WaitForCommit(round) waits for the block for round to be written to persistent storage. After WaitForCommit(round) returns, the ledger guarantees that the block will be present even after a crash.

  • Latest() returns the last block added to the ledger.

  • LatestCommitted() returns the last block written to durable storage.

  • Block(round) returns the block for round, or ErrNoEntry if no such block has been added. Similarly, BlockCert(round) will return the block and the associated certificate.

  • Wait(round) allows the caller to wait for a block to be added to the ledger for round, by returning a channel that will be closed when a block for round is added.

Tracker API

The ledger comes with a set of trackers. Each tracker maintains a state machine based on the blockchain contents. Trackers are logically stateless: that is, they can reconstruct their state by consuming all blocks from the beginning of the blockchain. As an optimization, the ledger allows trackers to store persistent state, so that they can reconstruct their state quickly, without considering every block.

The interface between ledger and trackers is defined in trackers.go.

Trackers have access to the ledger through a restricted API defined by ledgerForTracker. This allows trackers to access the ledger's SQLite database, to query for blocks, etc.

Conversely, the ledger accesses trackers through the ledgerTracker interface:

  • loadFromDisk(ledgerForTracker) initializes the state of the tracker. The tracker can use the ledgerForTracker argument to load persistent state (e.g., for the accounts database). The tracker can also query for recent blocks, if the tracker's state depends only on recent blocks (e.g., for the tracker that keeps track of the recently committed transactions).

  • newBlock(rnd, delta) tells the tracker about a new block added to the ledger. delta describes the changes made by this block; this will be described in more details under block evaluation later.

  • committedUpTo(rnd) tells the tracker that all blocks up to and including rnd are written to persistent storage. This call is important for trackers that store persistent state themselves, since the tracker must be able to restore its state correctly after a crash, and may need to answer queries about older blocks after a crash if some recent non-committed blocks are lost.

  • close() frees up any resources held by this tracker.

The ledger serializes all updates to the trackers with a reader-writer lock.

Trackers

An individual tracker exposes tracker-specific APIs for accessing the state maintained by that tracker. These are currently passed through the Ledger object, so that the ledger can provide appropriate reader-writer locking.

Account tracker
  • Lookup(round, address) uses the account tracker to look up the state of an account as of round.

  • AllBalances(round) uses the account tracker to return the set of all account states as of round. This is likely to be large, so it's intended for debug purposes only.

  • Totals(round) returns the totals of accounts, using the account tracker.

Time tracker
  • Timestamp(round) uses the time tracker to return the time as of round.
Recent transactions tracker
  • Committed(txnid) returns whether txid has been recently committed, using the transaction tail tracker.
Participation tracker
  • ParticipationThresholds() returns the participation thresholds, from the participation tracker.
Delegator tracker
  • DumpDelegatorsTree() returns the tree of delegators for offline rewards, from the delegator tracker, for debug purposes.
Notification tracker
  • RegisterBlockListeners(listeners) registers listeners for new blocks, based on the pools.BlockListener API.

Block evaluation

Finally, the ledger implements logic to evaluate blocks. It supports three functions:

  • Construct a new block, based on a pool of potential transactions and rewards, that will be valid. This is done by using the Ledger.StartEvaluator(hdr, txcache) method. This returns a BlockEvaluator, which can then accept tentative transactions and rewards (using BlockEvaluator.Transaction() and BlockEvaluator.Reward()). The caller can finalize the block by calling BlockEvaluator.GenerateBlock(). txcache represents a cache of previously verified transactions, to avoid repeated checking of transaction signatures.

  • Validate a block. This is done by calling Ledger.Validate(block, txcache). Under the covers, it executes the same logic using a BlockEvaluator.

  • Evaluate a block to produce a delta describing the changes that this block implies for all of the trackers. This is the delta passed to the newBlock() method of trackers.

Block evaluation also produces auxiliary state, evalAux, which describes the state needed to evaluate a block. Currently, this consists of the set of offline rewards. Computing evalAux may require access to past blocks or the old state of various state trackers (in particular, for the offline rewards, it requires access to the past state of the delegator tracker). However, given an evalAux, it is possible to evaluate the block. The BlockEvaluator computes the evalAux when first evaluating a block, and the ledger saves the evalAux state to re-evaluate the block after a crash as needed.

Documentation

Index

Constants

View Source
const MaxInt = int((^uint(0)) >> 1)

MaxInt is the maximum int which might be int32 or int64

Variables

View Source
var ErrNoSpace = errors.New("block does not have space for transaction")

ErrNoSpace indicates insufficient space for transaction in block

Functions

This section is empty.

Types

type AccountTotals

type AccountTotals struct {
	Online           AlgoCount
	Offline          AlgoCount
	NotParticipating AlgoCount

	// Total number of algos received per reward unit since genesis
	RewardsLevel uint64
}

AccountTotals represents the totals of algos in the system grouped by different account status values.

func (*AccountTotals) All

func (at *AccountTotals) All() basics.MicroAlgos

All returns the sum of algos held under all different status values.

func (*AccountTotals) Participating

func (at *AccountTotals) Participating() basics.MicroAlgos

Participating returns the sum of algos held under “participating” account status values (Online and Offline). It excludes MicroAlgos held by NotParticipating accounts.

func (*AccountTotals) RewardUnits

func (at *AccountTotals) RewardUnits() uint64

RewardUnits returns the sum of reward units held under “participating” account status values (Online and Offline). It excludes units held by NotParticipating accounts.

type AlgoCount

type AlgoCount struct {
	// Sum of algos of all accounts in this class.
	Money basics.MicroAlgos

	// Total number of whole reward units in accounts.
	RewardUnits uint64
}

AlgoCount represents a total of algos of a certain class of accounts (split up by their Status value).

type BlockEvaluator

type BlockEvaluator struct {
	// contains filtered or unexported fields
}

BlockEvaluator represents an in-progress evaluation of a block against the ledger.

func (*BlockEvaluator) GenerateBlock

func (eval *BlockEvaluator) GenerateBlock() (*ValidatedBlock, error)

GenerateBlock produces a complete block from the BlockEvaluator. This is used during proposal to get an actual block that will be proposed, after feeding in tentative transactions into this block evaluator.

func (*BlockEvaluator) ResetTxnBytes

func (eval *BlockEvaluator) ResetTxnBytes()

ResetTxnBytes resets the number of bytes tracked by the BlockEvaluator to zero. This is a specialized operation used by the transaction pool to simulate the effect of putting pending transactions in multiple blocks.

func (*BlockEvaluator) Round

func (eval *BlockEvaluator) Round() basics.Round

Round returns the round number of the block being evaluated by the BlockEvaluator.

func (*BlockEvaluator) TestTransactionGroup

func (eval *BlockEvaluator) TestTransactionGroup(txgroup []transactions.SignedTxn) error

TestTransactionGroup performs basic duplicate detection and well-formedness checks on a transaction group, but does not actually add the transactions to the block evaluator, or modify the block evaluator state in any other visible way.

func (*BlockEvaluator) Transaction

func (eval *BlockEvaluator) Transaction(txn transactions.SignedTxn, ad transactions.ApplyData) error

Transaction tentatively adds a new transaction as part of this block evaluation. If the transaction cannot be added to the block without violating some constraints, an error is returned and the block evaluator state is unchanged.

func (*BlockEvaluator) TransactionGroup

func (eval *BlockEvaluator) TransactionGroup(txads []transactions.SignedTxnWithAD) error

TransactionGroup tentatively adds a new transaction group as part of this block evaluation. If the transaction group cannot be added to the block without violating some constraints, an error is returned and the block evaluator state is unchanged.

type BlockInLedgerError

type BlockInLedgerError struct {
	LastRound basics.Round
	NextRound basics.Round
}

BlockInLedgerError is returned when a block cannot be added because it has already been done

func (BlockInLedgerError) Error

func (bile BlockInLedgerError) Error() string

Error satisfies builtin interface `error`

type BlockListener

type BlockListener interface {
	OnNewBlock(block bookkeeping.Block, delta StateDelta)
}

BlockListener represents an object that needs to get notified on new blocks.

type ErrNoEntry

type ErrNoEntry struct {
	Round     basics.Round
	Latest    basics.Round
	Committed basics.Round
}

ErrNoEntry is used to indicate that a block is not present in the ledger.

func (ErrNoEntry) Error

func (err ErrNoEntry) Error() string

Error satisfies builtin interface `error`

type InitState

type InitState struct {
	Block       bookkeeping.Block
	Accounts    map[basics.Address]basics.AccountData
	GenesisHash crypto.Digest
}

InitState structure defines blockchain init params

type Ledger

type Ledger struct {
	// contains filtered or unexported fields
}

Ledger is a database storing the contents of the ledger.

func OpenLedger

func OpenLedger(
	log logging.Logger, dbPathPrefix string, dbMem bool, genesisInitState InitState, isArchival bool,
) (*Ledger, error)

OpenLedger creates a Ledger object, using SQLite database filenames based on dbPathPrefix (in-memory if dbMem is true). genesisInitState.Blocks and genesisInitState.Accounts specify the initial blocks and accounts to use if the database wasn't initialized before.

func (*Ledger) AddBlock

func (l *Ledger) AddBlock(blk bookkeeping.Block, cert agreement.Certificate) error

AddBlock adds a new block to the ledger. The block is stored in an in-memory queue and is written to the disk in the background. An error is returned if this is not the expected next block number.

func (*Ledger) AddValidatedBlock

func (l *Ledger) AddValidatedBlock(vb ValidatedBlock, cert agreement.Certificate) error

AddValidatedBlock adds a new block to the ledger, after the block has been validated by calling Ledger.Validate(). This saves the cost of having to re-compute the effect of the block on the ledger state, if the block has previously been validated. Otherwise, AddValidatedBlock behaves like AddBlock.

func (*Ledger) AllBalances

func (l *Ledger) AllBalances(rnd basics.Round) (map[basics.Address]basics.AccountData, error)

AllBalances returns a map of every account balance as of round rnd.

func (*Ledger) Block

func (l *Ledger) Block(rnd basics.Round) (blk bookkeeping.Block, err error)

Block returns the block for round rnd.

func (*Ledger) BlockCert

func (l *Ledger) BlockCert(rnd basics.Round) (blk bookkeeping.Block, cert agreement.Certificate, err error)

BlockCert returns the block and the certificate of the block for round rnd.

func (*Ledger) BlockHdr

func (l *Ledger) BlockHdr(rnd basics.Round) (blk bookkeeping.BlockHeader, err error)

BlockHdr returns the BlockHeader of the block for round rnd.

func (*Ledger) Close

func (l *Ledger) Close()

Close reclaims resources used by the ledger (namely, the database connection and goroutines used by trackers).

func (*Ledger) EncodedBlockCert

func (l *Ledger) EncodedBlockCert(rnd basics.Round) (blk []byte, cert []byte, err error)

EncodedBlockCert returns the encoded block and the corresponding encoded certificate of the block for round rnd.

func (*Ledger) GenesisHash

func (l *Ledger) GenesisHash() crypto.Digest

GenesisHash returns the genesis hash for this ledger.

func (*Ledger) GetAssetCreator

func (l *Ledger) GetAssetCreator(assetIdx basics.AssetIndex) (basics.Address, error)

GetAssetCreator is like GetAssetCreatorForRound, but for the latest round and race free with respect to ledger.Latest()

func (*Ledger) GetAssetCreatorForRound

func (l *Ledger) GetAssetCreatorForRound(rnd basics.Round, assetIdx basics.AssetIndex) (basics.Address, error)

GetAssetCreatorForRound looks up the asset creator given the numerical asset ID. This is necessary so that we can retrieve the AssetParams from the creator's balance record.

func (*Ledger) GetRoundTxIds

func (l *Ledger) GetRoundTxIds(rnd basics.Round) (txMap map[transactions.Txid]bool)

GetRoundTxIds returns a map of the transactions ids that we have for the given round

func (*Ledger) Latest

func (l *Ledger) Latest() basics.Round

Latest returns the latest known block round added to the ledger.

func (*Ledger) LatestCommitted

func (l *Ledger) LatestCommitted() basics.Round

LatestCommitted returns the last block round number written to persistent storage. This block, and all previous blocks, are guaranteed to be available after a crash.

func (*Ledger) ListAssets

func (l *Ledger) ListAssets(maxAssetIdx basics.AssetIndex, maxResults uint64) (results []basics.AssetLocator, err error)

ListAssets takes a maximum asset index and maximum result length, and returns up to that many asset AssetIDs from the database where asset id is less than or equal to the maximum.

func (*Ledger) Lookup

func (l *Ledger) Lookup(rnd basics.Round, addr basics.Address) (basics.AccountData, error)

Lookup uses the accounts tracker to return the account state for a given account in a particular round. The account values reflect the changes of all blocks up to and including rnd.

func (*Ledger) LookupWithoutRewards

func (l *Ledger) LookupWithoutRewards(rnd basics.Round, addr basics.Address) (basics.AccountData, error)

LookupWithoutRewards is like Lookup but does not apply pending rewards up to the requested round rnd.

func (*Ledger) RegisterBlockListeners

func (l *Ledger) RegisterBlockListeners(listeners []BlockListener)

RegisterBlockListeners registers listeners that will be called when a new block is added to the ledger.

func (*Ledger) StartEvaluator

func (l *Ledger) StartEvaluator(hdr bookkeeping.BlockHeader, txcache VerifiedTxnCache, executionPool execpool.BacklogPool) (*BlockEvaluator, error)

StartEvaluator creates a BlockEvaluator, given a ledger and a block header of the block that the caller is planning to evaluate.

func (*Ledger) Timestamp

func (l *Ledger) Timestamp(r basics.Round) (int64, error)

Timestamp uses the timestamp tracker to return the timestamp from block r.

func (*Ledger) Totals

func (l *Ledger) Totals(rnd basics.Round) (AccountTotals, error)

Totals returns the totals of all accounts at the end of round rnd.

func (*Ledger) Validate

func (l *Ledger) Validate(ctx context.Context, blk bookkeeping.Block, txcache VerifiedTxnCache, executionPool execpool.BacklogPool) (*ValidatedBlock, error)

Validate uses the ledger to validate block blk as a candidate next block. It returns an error if blk is not the expected next block, or if blk is not a valid block (e.g., it has duplicate transactions, overspends some account, etc).

func (*Ledger) Wait

func (l *Ledger) Wait(r basics.Round) chan struct{}

Wait returns a channel that closes once a given round is stored durably in the ledger. When <-l.Wait(r) finishes, ledger is guaranteed to have round r, and will not lose round r after a crash. This makes it easy to use in a select{} statement.

func (*Ledger) WaitForCommit

func (l *Ledger) WaitForCommit(r basics.Round)

WaitForCommit waits until block r (and block before r) are durably written to disk.

type ProtocolError

type ProtocolError protocol.ConsensusVersion

ProtocolError is used to indicate that an unsupported protocol has been detected.

func (ProtocolError) Error

func (err ProtocolError) Error() string

Error satisfies builtin interface `error`

type StateDelta

type StateDelta struct {

	// new Txids for the txtail and TxnCounter, mapped to txn.LastValid
	Txids map[transactions.Txid]basics.Round
	// contains filtered or unexported fields
}

StateDelta describes the delta between a given round to the previous round

type TransactionInLedgerError

type TransactionInLedgerError struct {
	Txid transactions.Txid
}

TransactionInLedgerError is returned when a transaction cannot be added because it has already been done

func (TransactionInLedgerError) Error

func (tile TransactionInLedgerError) Error() string

Error satisfies builtin interface `error`

type ValidatedBlock

type ValidatedBlock struct {
	// contains filtered or unexported fields
}

ValidatedBlock represents the result of a block validation. It can be used to efficiently add the block to the ledger, without repeating the work of applying the block's changes to the ledger state.

func (ValidatedBlock) Block

func (vb ValidatedBlock) Block() bookkeeping.Block

Block returns the underlying Block for a ValidatedBlock.

func (ValidatedBlock) WithSeed

WithSeed returns a copy of the ValidatedBlock with a modified seed.

type VerifiedTxnCache

type VerifiedTxnCache interface {
	Verified(txn transactions.SignedTxn) bool
	EvalOk(cvers protocol.ConsensusVersion, txid transactions.Txid) (found bool, txErr error)
	EvalRemember(cvers protocol.ConsensusVersion, txid transactions.Txid, err error)
}

VerifiedTxnCache captures the interface for a cache of previously verified transactions. This is expected to match the transaction pool object.

Jump to

Keyboard shortcuts

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