Skip to content

Commit

Permalink
StateProofs: Use stateproof tracker (#4733)
Browse files Browse the repository at this point in the history
* add version to the verification structure and new consensus param

* refactor state proof verifcaion

* apply state proof using trakcer

* export stateproof verification data in LedgerForCowBase interface

* using tracker on tests.

* fix ledger test

* fix borken interface

* choose to use the tracker based on atRound proto version

* fix tests

* testing v34

* refactoring

* fix comments
  • Loading branch information
id-ms committed Nov 6, 2022
1 parent e569879 commit 0bd34b8
Show file tree
Hide file tree
Showing 20 changed files with 361 additions and 115 deletions.
4 changes: 4 additions & 0 deletions cmd/tealdbg/localLedger.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ func (l *localLedger) BlockHdrCached(basics.Round) (bookkeeping.BlockHeader, err
return bookkeeping.BlockHeader{}, nil
}

func (l *localLedger) StateProofVerificationData(_ basics.Round) (*ledgercore.StateProofVerificationData, error) {
return nil, fmt.Errorf("localLedger: StateProofVerificationData is not implemented")
}

func (l *localLedger) CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledgercore.Txlease) error {
return nil
}
Expand Down
6 changes: 6 additions & 0 deletions config/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,10 @@ type ConsensusParams struct {
// the rewardsLevel, but the rewardsLevel has no meaning because the account
// has fewer than RewardUnit algos.
UnfundedSenders bool

// StateProofUseTrackerVerification specifies whether the node will use data from state proof verification tracker
// in order to verify state proofs.
StateProofUseTrackerVerification bool
}

// PaysetCommitType enumerates possible ways for the block header to commit to
Expand Down Expand Up @@ -1250,6 +1254,8 @@ func initConsensusProtocols() {

vFuture.LogicSigVersion = 9 // When moving this to a release, put a new higher LogicSigVersion here

vFuture.StateProofUseTrackerVerification = true

Consensus[protocol.ConsensusFuture] = vFuture

// vAlphaX versions are an separate series of consensus parameters and versions for alphanet
Expand Down
6 changes: 5 additions & 1 deletion daemon/algod/api/server/v2/dryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ func (dl *dryrunLedger) CheckDup(config.ConsensusParams, basics.Round, basics.Ro
return nil
}

func (dl *dryrunLedger) StateProofVerificationData(_ basics.Round) (*ledgercore.StateProofVerificationData, error) {
return nil, fmt.Errorf("dryrunLedger: StateProofVerificationData is not implemented")
}

func (dl *dryrunLedger) lookup(rnd basics.Round, addr basics.Address) (basics.AccountData, basics.Round, error) {
// check accounts from debug records uploaded
out := basics.AccountData{}
Expand Down Expand Up @@ -474,7 +478,7 @@ func doDryrunRequest(dr *DryrunRequest, response *generated.DryrunResponse) {
}
}
if !found {
(*acct.AppsLocalState) = append(*acct.AppsLocalState, ls)
*acct.AppsLocalState = append(*acct.AppsLocalState, ls)
}
}
dl.dr.Accounts[idx] = acct
Expand Down
5 changes: 5 additions & 0 deletions ledger/acctupdates.go
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,11 @@ func (aul *accountUpdatesLedgerEvaluator) VotersForStateProof(rnd basics.Round)
return aul.ao.voters.getVoters(rnd)
}

func (aul *accountUpdatesLedgerEvaluator) StateProofVerificationData(_ basics.Round) (*ledgercore.StateProofVerificationData, error) {
// this function should not be used by accountUpdatesLedgerEvaluator
return nil, fmt.Errorf("accountUpdatesLedgerEvaluator: tried to get stateProofVerification data during accountUpdates initialization ")
}

// BlockHdr returns the header of the given round. When the evaluator is running, it's only referring to the previous header, which is what we
// are providing here. Any attempt to access a different header would get denied.
func (aul *accountUpdatesLedgerEvaluator) BlockHdr(r basics.Round) (bookkeeping.BlockHeader, error) {
Expand Down
1 change: 1 addition & 0 deletions ledger/apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type StateProofsApplier interface {
BlockHdr(r basics.Round) (bookkeeping.BlockHeader, error)
GetStateProofNextRound() basics.Round
SetStateProofNextRound(rnd basics.Round)
StateProofVerificationData(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationData, error)
}

// Balances allow to move MicroAlgos from one address to another and to update balance records, or to access and modify individual balance records
Expand Down
54 changes: 39 additions & 15 deletions ledger/apply/stateproof.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/stateproof/verify"
)
Expand All @@ -41,31 +42,54 @@ func StateProof(tx transactions.StateProofTxnFields, atRound basics.Round, sp St
}

lastRoundInInterval := basics.Round(tx.Message.LastAttestedRound)
lastRoundHdr, err := sp.BlockHdr(lastRoundInInterval)
if err != nil {
return err
}

nextStateProofRnd := sp.GetStateProofNextRound()
if nextStateProofRnd == 0 || nextStateProofRnd != lastRoundInInterval {
return fmt.Errorf("applyStateProof: %w - expecting state proof for %d, but new state proof is for %d",
ErrExpectedDifferentStateProofRound, nextStateProofRnd, lastRoundInInterval)
}

proto := config.Consensus[lastRoundHdr.CurrentProtocol]
if validate {
votersRnd := lastRoundInInterval.SubSaturate(basics.Round(proto.StateProofInterval))
votersHdr, err := sp.BlockHdr(votersRnd)
if err != nil {
return err
}
atRoundHdr, err := sp.BlockHdr(atRound)
if err != nil {
return err
}

var verificationData *ledgercore.StateProofVerificationData
if config.Consensus[atRoundHdr.CurrentProtocol].StateProofUseTrackerVerification {
verificationData, err = sp.StateProofVerificationData(lastRoundInInterval)
} else {
verificationData, err = gatherVerificationDataUsingBlockHeaders(sp, lastRoundInInterval)
}
if err != nil {
return err
}

err = verify.ValidateStateProof(&lastRoundHdr, &tx.StateProof, &votersHdr, atRound, &tx.Message)
if err != nil {
if validate {
if err = verify.ValidateStateProof(verificationData, &tx.StateProof, atRound, &tx.Message); err != nil {
return err
}
}

sp.SetStateProofNextRound(lastRoundInInterval + basics.Round(proto.StateProofInterval))
sp.SetStateProofNextRound(lastRoundInInterval + basics.Round(config.Consensus[verificationData.Version].StateProofInterval))
return nil
}

func gatherVerificationDataUsingBlockHeaders(sp StateProofsApplier, lastRoundInInterval basics.Round) (*ledgercore.StateProofVerificationData, error) {
lastRoundHdr, err := sp.BlockHdr(lastRoundInInterval)
if err != nil {
return nil, err
}
proto := config.Consensus[lastRoundHdr.CurrentProtocol]
votersRnd := lastRoundInInterval.SubSaturate(basics.Round(proto.StateProofInterval))
votersHdr, err := sp.BlockHdr(votersRnd)
if err != nil {
return nil, err
}

verificationData := ledgercore.StateProofVerificationData{
TargetStateProofRound: lastRoundInInterval,
VotersCommitment: votersHdr.StateProofTracking[protocol.StateProofBasic].StateProofVotersCommitment,
OnlineTotalWeight: votersHdr.StateProofTracking[protocol.StateProofBasic].StateProofOnlineTotalWeight,
Version: votersHdr.CurrentProtocol,
}
return &verificationData, nil
}
6 changes: 6 additions & 0 deletions ledger/evalindexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ func (l indexerLedgerConnector) VotersForStateProof(_ basics.Round) (*ledgercore
return nil, errors.New("VotersForStateProof() not implemented")
}

// StateProofVerificationData is part of LedgerForEvaluator interface.
func (l indexerLedgerConnector) StateProofVerificationData(_ basics.Round) (*ledgercore.StateProofVerificationData, error) {
// This function is not used by evaluator.
return nil, errors.New("StateProofVerificationData() not implemented")
}

func makeIndexerLedgerConnector(il indexerLedgerForEval, genesisHash crypto.Digest, genesisProto config.ConsensusParams, latestRound basics.Round, roundResources EvalForIndexerResources) indexerLedgerConnector {
return indexerLedgerConnector{
il: il,
Expand Down
4 changes: 4 additions & 0 deletions ledger/internal/appcow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ func (ml *emptyLedger) GetStateProofNextRound() basics.Round {
return basics.Round(0)
}

func (ml *emptyLedger) StateProofVerificationData(_ basics.Round) (*ledgercore.StateProofVerificationData, error) {
return nil, fmt.Errorf("emptyLedger does not implement StateProofVerificationData")
}

type modsData struct {
addr basics.Address
cidx basics.CreatableIndex
Expand Down
6 changes: 5 additions & 1 deletion ledger/internal/cow.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ type roundCowParent interface {
getStorageLimits(addr basics.Address, aidx basics.AppIndex, global bool) (basics.StateSchema, error)
allocated(addr basics.Address, aidx basics.AppIndex, global bool) (bool, error)
getKey(addr basics.Address, aidx basics.AppIndex, global bool, key string, accountIdx uint64) (basics.TealValue, bool, error)

kvGet(key string) ([]byte, bool, error)
StateProofVerificationData(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationData, error)
}

type roundCowState struct {
Expand Down Expand Up @@ -241,6 +241,10 @@ func (cb *roundCowState) BlockHdr(r basics.Round) (bookkeeping.BlockHeader, erro
return cb.lookupParent.BlockHdr(r)
}

func (cb *roundCowState) StateProofVerificationData(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationData, error) {
return cb.lookupParent.StateProofVerificationData(stateProofLastAttestedRound)
}

func (cb *roundCowState) blockHdrCached(r basics.Round) (bookkeeping.BlockHeader, error) {
return cb.lookupParent.blockHdrCached(r)
}
Expand Down
16 changes: 13 additions & 3 deletions ledger/internal/cow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package internal

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -32,9 +33,10 @@ import (
)

type mockLedger struct {
balanceMap map[basics.Address]basics.AccountData
blocks map[basics.Round]bookkeeping.BlockHeader
blockErr map[basics.Round]error
balanceMap map[basics.Address]basics.AccountData
blocks map[basics.Round]bookkeeping.BlockHeader
blockErr map[basics.Round]error
stateProofVerification map[basics.Round]*ledgercore.StateProofVerificationData
}

func (ml *mockLedger) lookup(addr basics.Address) (ledgercore.AccountData, error) {
Expand Down Expand Up @@ -110,6 +112,14 @@ func (ml *mockLedger) blockHdrCached(rnd basics.Round) (bookkeeping.BlockHeader,
return ml.blockHdrCached(rnd)
}

func (ml *mockLedger) StateProofVerificationData(rnd basics.Round) (*ledgercore.StateProofVerificationData, error) {
element, exists := ml.stateProofVerification[rnd]
if !exists {
return nil, fmt.Errorf("requested state proof verification data not found")
}
return element, nil
}

func checkCowByUpdate(t *testing.T, cow *roundCowState, delta ledgercore.AccountDeltas) {
for i := 0; i < delta.Len(); i++ {
addr, data := delta.GetByIdx(i)
Expand Down
5 changes: 5 additions & 0 deletions ledger/internal/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type LedgerForCowBase interface {
LookupApplication(basics.Round, basics.Address, basics.AppIndex) (ledgercore.AppResource, error)
LookupKv(basics.Round, string) ([]byte, error)
GetCreatorForRound(basics.Round, basics.CreatableIndex, basics.CreatableType) (basics.Address, bool, error)
StateProofVerificationData(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationData, error)
}

// ErrRoundZero is self-explanatory
Expand Down Expand Up @@ -337,6 +338,10 @@ func (x *roundCowBase) BlockHdr(r basics.Round) (bookkeeping.BlockHeader, error)
return x.l.BlockHdr(r)
}

func (x *roundCowBase) StateProofVerificationData(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationData, error) {
return x.l.StateProofVerificationData(stateProofLastAttestedRound)
}

func (x *roundCowBase) blockHdrCached(r basics.Round) (bookkeeping.BlockHeader, error) {
return x.l.BlockHdrCached(r)
}
Expand Down
Loading

0 comments on commit 0bd34b8

Please sign in to comment.