summaryrefslogtreecommitdiff
path: root/ledger/ledger.go
diff options
context:
space:
mode:
Diffstat (limited to 'ledger/ledger.go')
-rw-r--r--ledger/ledger.go176
1 files changed, 135 insertions, 41 deletions
diff --git a/ledger/ledger.go b/ledger/ledger.go
index e69c3c355..4c0ececaa 100644
--- a/ledger/ledger.go
+++ b/ledger/ledger.go
@@ -28,13 +28,18 @@ import (
"github.com/algorand/go-algorand/agreement"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
+ "github.com/algorand/go-algorand/crypto/compactcert"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/data/transactions/verify"
+ "github.com/algorand/go-algorand/ledger/apply"
+ "github.com/algorand/go-algorand/ledger/internal"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/logging"
+ "github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/util/db"
+ "github.com/algorand/go-algorand/util/execpool"
"github.com/algorand/go-algorand/util/metrics"
)
@@ -70,11 +75,12 @@ type Ledger struct {
genesisProto config.ConsensusParams
// State-machine trackers
- accts accountUpdates
- txTail txTail
- bulletin bulletin
- notifier blockNotifier
- metrics metricsTracker
+ accts accountUpdates
+ catchpoint catchpointTracker
+ txTail txTail
+ bulletin bulletin
+ notifier blockNotifier
+ metrics metricsTracker
trackers trackerRegistry
trackerMu deadlock.RWMutex
@@ -83,13 +89,8 @@ type Ledger struct {
// verifiedTxnCache holds all the verified transactions state
verifiedTxnCache verify.VerifiedTransactionCache
-}
-// InitState structure defines blockchain init params
-type InitState struct {
- Block bookkeeping.Block
- Accounts map[basics.Address]basics.AccountData
- GenesisHash crypto.Digest
+ cfg config.Local
}
// OpenLedger creates a Ledger object, using SQLite database filenames
@@ -97,7 +98,7 @@ type InitState struct {
// genesisInitState.Accounts specify the initial blocks and accounts to use if the
// database wasn't initialized before.
func OpenLedger(
- log logging.Logger, dbPathPrefix string, dbMem bool, genesisInitState InitState, cfg config.Local,
+ log logging.Logger, dbPathPrefix string, dbMem bool, genesisInitState ledgercore.InitState, cfg config.Local,
) (*Ledger, error) {
var err error
verifiedCacheSize := cfg.VerifiedTranscationsCacheSize
@@ -115,6 +116,7 @@ func OpenLedger(
synchronousMode: db.SynchronousMode(cfg.LedgerSynchronousMode),
accountsRebuildSynchronousMode: db.SynchronousMode(cfg.AccountsRebuildSynchronousMode),
verifiedTxnCache: verify.MakeVerifiedTransactionCache(verifiedCacheSize),
+ cfg: cfg,
}
l.headerCache.maxEntries = 10
@@ -152,7 +154,8 @@ func OpenLedger(
l.genesisAccounts = make(map[basics.Address]basics.AccountData)
}
- l.accts.initialize(cfg, dbPathPrefix, l.genesisProto, l.genesisAccounts)
+ l.accts.initialize(cfg)
+ l.catchpoint.initialize(cfg, dbPathPrefix)
err = l.reloadLedger()
if err != nil {
@@ -178,7 +181,7 @@ func (l *Ledger) reloadLedger() error {
// close the trackers.
l.trackers.close()
- // reload -
+ // init block queue
var err error
l.blockQ, err = bqInit(l)
if err != nil {
@@ -186,11 +189,26 @@ func (l *Ledger) reloadLedger() error {
return err
}
- l.trackers.register(&l.accts) // update the balances
- l.trackers.register(&l.txTail) // update the transaction tail, tracking the recent 1000 txn
- l.trackers.register(&l.bulletin) // provide closed channel signaling support for completed rounds
- l.trackers.register(&l.notifier) // send OnNewBlocks to subscribers
- l.trackers.register(&l.metrics) // provides metrics reporting support
+ // init tracker db
+ trackerDBInitParams, err := trackerDBInitialize(l, l.catchpoint.catchpointEnabled(), l.catchpoint.dbDirectory)
+ if err != nil {
+ return err
+ }
+
+ // set account updates tracker as a driver to calculate tracker db round and committing offsets
+ trackers := []ledgerTracker{
+ &l.accts, // update the balances
+ &l.catchpoint, // catchpoints tracker : update catchpoint labels, create catchpoint files
+ &l.txTail, // update the transaction tail, tracking the recent 1000 txn
+ &l.bulletin, // provide closed channel signaling support for completed rounds
+ &l.notifier, // send OnNewBlocks to subscribers
+ &l.metrics, // provides metrics reporting support
+ }
+
+ err = l.trackers.initialize(l, trackers, l.cfg)
+ if err != nil {
+ return err
+ }
err = l.trackers.loadFromDisk(l)
if err != nil {
@@ -198,6 +216,14 @@ func (l *Ledger) reloadLedger() error {
return err
}
+ // post-init actions
+ if trackerDBInitParams.vacuumOnStartup || l.cfg.OptimizeAccountsDatabaseOnStartup {
+ err = l.accts.vacuumDatabase(context.Background())
+ if err != nil {
+ return err
+ }
+ }
+
// Check that the genesis hash, if present, matches.
err = l.verifyMatchingGenesisHash()
if err != nil {
@@ -384,7 +410,7 @@ func (l *Ledger) notifyCommit(r basics.Round) basics.Round {
func (l *Ledger) GetLastCatchpointLabel() string {
l.trackerMu.RLock()
defer l.trackerMu.RUnlock()
- return l.accts.GetLastCatchpointLabel()
+ return l.catchpoint.GetLastCatchpointLabel()
}
// GetCreatorForRound takes a CreatableIndex and a CreatableType and tries to
@@ -407,7 +433,7 @@ func (l *Ledger) GetCreator(cidx basics.CreatableIndex, ctype basics.CreatableTy
// CompactCertVoters returns the top online accounts at round rnd.
// The result might be nil, even with err=nil, if there are no voters
// for that round because compact certs were not enabled.
-func (l *Ledger) CompactCertVoters(rnd basics.Round) (voters *VotersForRound, err error) {
+func (l *Ledger) CompactCertVoters(rnd basics.Round) (*ledgercore.VotersForRound, error) {
l.trackerMu.RLock()
defer l.trackerMu.RUnlock()
return l.accts.voters.getVoters(rnd)
@@ -447,6 +473,20 @@ func (l *Ledger) Lookup(rnd basics.Round, addr basics.Address) (basics.AccountDa
return data, nil
}
+// LookupAgreement returns account data used by agreement.
+func (l *Ledger) LookupAgreement(rnd basics.Round, addr basics.Address) (basics.OnlineAccountData, error) {
+ l.trackerMu.RLock()
+ defer l.trackerMu.RUnlock()
+
+ // Intentionally apply (pending) rewards up to rnd.
+ data, err := l.accts.LookupWithRewards(rnd, addr)
+ if err != nil {
+ return basics.OnlineAccountData{}, err
+ }
+
+ return data.OnlineAccountData(), nil
+}
+
// LookupWithoutRewards is like Lookup but does not apply pending rewards up
// to the requested round rnd.
func (l *Ledger) LookupWithoutRewards(rnd basics.Round, addr basics.Address) (basics.AccountData, basics.Round, error) {
@@ -480,10 +520,10 @@ func (l *Ledger) OnlineTotals(rnd basics.Round) (basics.MicroAlgos, error) {
}
// CheckDup return whether a transaction is a duplicate one.
-func (l *Ledger) CheckDup(currentProto config.ConsensusParams, current basics.Round, firstValid basics.Round, lastValid basics.Round, txid transactions.Txid, txl TxLease) error {
+func (l *Ledger) CheckDup(currentProto config.ConsensusParams, current basics.Round, firstValid basics.Round, lastValid basics.Round, txid transactions.Txid, txl ledgercore.Txlease) error {
l.trackerMu.RLock()
defer l.trackerMu.RUnlock()
- return l.txTail.checkDup(currentProto, current, firstValid, lastValid, txid, txl.Txlease)
+ return l.txTail.checkDup(currentProto, current, firstValid, lastValid, txid, txl)
}
// Latest returns the latest known block round added to the ledger.
@@ -536,15 +576,11 @@ func (l *Ledger) BlockCert(rnd basics.Round) (blk bookkeeping.Block, cert agreem
func (l *Ledger) AddBlock(blk bookkeeping.Block, cert agreement.Certificate) error {
// passing nil as the executionPool is ok since we've asking the evaluator to skip verification.
- updates, err := eval(context.Background(), l, blk, false, l.verifiedTxnCache, nil)
+ updates, err := internal.Eval(context.Background(), l, blk, false, l.verifiedTxnCache, nil)
if err != nil {
return err
}
-
- vb := ValidatedBlock{
- blk: blk,
- delta: updates,
- }
+ vb := ledgercore.MakeValidatedBlock(blk, updates)
return l.AddValidatedBlock(vb, cert)
}
@@ -554,18 +590,19 @@ func (l *Ledger) AddBlock(blk bookkeeping.Block, cert agreement.Certificate) err
// 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 (l *Ledger) AddValidatedBlock(vb ValidatedBlock, cert agreement.Certificate) error {
+func (l *Ledger) AddValidatedBlock(vb ledgercore.ValidatedBlock, cert agreement.Certificate) error {
// Grab the tracker lock first, to ensure newBlock() is notified before committedUpTo().
l.trackerMu.Lock()
defer l.trackerMu.Unlock()
- err := l.blockQ.putBlock(vb.blk, cert)
+ blk := vb.Block()
+ err := l.blockQ.putBlock(blk, cert)
if err != nil {
return err
}
- l.headerCache.Put(vb.blk.Round(), vb.blk.BlockHeader)
- l.trackers.newBlock(vb.blk, vb.delta)
- l.log.Debugf("added blk %d", vb.blk.Round())
+ l.headerCache.Put(blk.Round(), blk.BlockHeader)
+ l.trackers.newBlock(blk, vb.Delta())
+ l.log.Debugf("added blk %d", blk.Round())
return nil
}
@@ -596,6 +633,11 @@ func (l *Ledger) GenesisProto() config.ConsensusParams {
return l.genesisProto
}
+// GenesisAccounts returns initial accounts for this ledger.
+func (l *Ledger) GenesisAccounts() map[basics.Address]basics.AccountData {
+ return l.genesisAccounts
+}
+
// GetCatchpointCatchupState returns the current state of the catchpoint catchup.
func (l *Ledger) GetCatchpointCatchupState(ctx context.Context) (state CatchpointCatchupState, err error) {
return MakeCatchpointCatchupAccessor(l, l.log).GetState(ctx)
@@ -609,7 +651,7 @@ func (l *Ledger) GetCatchpointCatchupState(ctx context.Context) (state Catchpoin
func (l *Ledger) GetCatchpointStream(round basics.Round) (ReadCloseSizer, error) {
l.trackerMu.RLock()
defer l.trackerMu.RUnlock()
- return l.accts.GetCatchpointStream(round)
+ return l.catchpoint.GetCatchpointStream(round)
}
// ledgerForTracker methods
@@ -629,9 +671,9 @@ func (l *Ledger) trackerLog() logging.Logger {
// trackerEvalVerified is used by the accountUpdates to reconstruct the ledgercore.StateDelta from a given block during it's loadFromDisk execution.
// when this function is called, the trackers mutex is expected already to be taken. The provided accUpdatesLedger would allow the
// evaluator to shortcut the "main" ledger ( i.e. this struct ) and avoid taking the trackers lock a second time.
-func (l *Ledger) trackerEvalVerified(blk bookkeeping.Block, accUpdatesLedger ledgerForEvaluator) (ledgercore.StateDelta, error) {
+func (l *Ledger) trackerEvalVerified(blk bookkeeping.Block, accUpdatesLedger internal.LedgerForEvaluator) (ledgercore.StateDelta, error) {
// passing nil as the executionPool is ok since we've asking the evaluator to skip verification.
- return eval(context.Background(), accUpdatesLedger, blk, false, l.verifiedTxnCache, nil)
+ return internal.Eval(context.Background(), accUpdatesLedger, blk, false, l.verifiedTxnCache, nil)
}
// IsWritingCatchpointFile returns true when a catchpoint file is being generated. The function is used by the catchup service
@@ -639,7 +681,7 @@ func (l *Ledger) trackerEvalVerified(blk bookkeeping.Block, accUpdatesLedger led
func (l *Ledger) IsWritingCatchpointFile() bool {
l.trackerMu.RLock()
defer l.trackerMu.RUnlock()
- return l.accts.IsWritingCatchpointFile()
+ return l.catchpoint.IsWritingCatchpointFile()
}
// VerifiedTransactionCache returns the verify.VerifiedTransactionCache
@@ -647,9 +689,61 @@ func (l *Ledger) VerifiedTransactionCache() verify.VerifiedTransactionCache {
return l.verifiedTxnCache
}
-// TxLease is an exported version of txlease
-type TxLease struct {
- ledgercore.Txlease
+// StartEvaluator creates a BlockEvaluator, given a ledger and a block header
+// of the block that the caller is planning to evaluate. If the length of the
+// payset being evaluated is known in advance, a paysetHint >= 0 can be
+// passed, avoiding unnecessary payset slice growth. The optional maxTxnBytesPerBlock parameter
+// provides a cap on the size of a single generated block size, when a non-zero value is passed.
+// If a value of zero or less is passed to maxTxnBytesPerBlock, the consensus MaxTxnBytesPerBlock would
+// be used instead.
+func (l *Ledger) StartEvaluator(hdr bookkeeping.BlockHeader, paysetHint, maxTxnBytesPerBlock int) (*internal.BlockEvaluator, error) {
+ return internal.StartEvaluator(l, hdr,
+ internal.EvaluatorOptions{
+ PaysetHint: paysetHint,
+ Generate: true,
+ Validate: true,
+ MaxTxnBytesPerBlock: maxTxnBytesPerBlock,
+ })
+}
+
+// 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 (l *Ledger) Validate(ctx context.Context, blk bookkeeping.Block, executionPool execpool.BacklogPool) (*ledgercore.ValidatedBlock, error) {
+ delta, err := internal.Eval(ctx, l, blk, true, l.verifiedTxnCache, executionPool)
+ if err != nil {
+ return nil, err
+ }
+
+ vb := ledgercore.MakeValidatedBlock(blk, delta)
+ return &vb, nil
+}
+
+// CompactCertParams computes the parameters for building or verifying
+// a compact cert for block hdr, using voters from block votersHdr.
+func CompactCertParams(votersHdr bookkeeping.BlockHeader, hdr bookkeeping.BlockHeader) (res compactcert.Params, err error) {
+ return internal.CompactCertParams(votersHdr, hdr)
+}
+
+// AcceptableCompactCertWeight computes the acceptable signed weight
+// of a compact cert if it were to appear in a transaction with a
+// particular firstValid round. Earlier rounds require a smaller cert.
+// votersHdr specifies the block that contains the Merkle commitment of
+// the voters for this compact cert (and thus the compact cert is for
+// votersHdr.Round() + CompactCertRounds).
+//
+// logger must not be nil; use at least logging.Base()
+func AcceptableCompactCertWeight(votersHdr bookkeeping.BlockHeader, firstValid basics.Round, logger logging.Logger) uint64 {
+ return internal.AcceptableCompactCertWeight(votersHdr, firstValid, logger)
+}
+
+// DebuggerLedger defines the minimal set of method required for creating a debug balances.
+type DebuggerLedger = internal.LedgerForCowBase
+
+// MakeDebugBalances creates a ledger suitable for dryrun and debugger
+func MakeDebugBalances(l DebuggerLedger, round basics.Round, proto protocol.ConsensusVersion, prevTimestamp int64) apply.Balances {
+ return internal.MakeDebugBalances(l, round, proto, prevTimestamp)
}
var ledgerInitblocksdbCount = metrics.NewCounter("ledger_initblocksdb_count", "calls")