diff --git a/cmd/tealdbg/localLedger.go b/cmd/tealdbg/localLedger.go index 64dfe7329d..fc7655173f 100644 --- a/cmd/tealdbg/localLedger.go +++ b/cmd/tealdbg/localLedger.go @@ -281,6 +281,10 @@ func (l *localLedger) BlockHdr(basics.Round) (bookkeeping.BlockHeader, error) { return bookkeeping.BlockHeader{}, nil } +func (l *localLedger) GenesisHash() crypto.Digest { + return crypto.Digest{} +} + func (l *localLedger) GetStateProofVerificationContext(_ basics.Round) (*ledgercore.StateProofVerificationContext, error) { return nil, fmt.Errorf("localLedger: GetStateProofVerificationContext, needed for state proof verification, is not implemented in debugger") } diff --git a/daemon/algod/api/server/v2/dryrun.go b/daemon/algod/api/server/v2/dryrun.go index ef0de80850..acf5fc94b7 100644 --- a/daemon/algod/api/server/v2/dryrun.go +++ b/daemon/algod/api/server/v2/dryrun.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/algorand/go-algorand/config" + "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/model" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" @@ -241,6 +242,10 @@ func (dl *dryrunLedger) BlockHdr(basics.Round) (bookkeeping.BlockHeader, error) return bookkeeping.BlockHeader{}, nil } +func (dl *dryrunLedger) GenesisHash() crypto.Digest { + return crypto.Digest{} +} + func (dl *dryrunLedger) CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledgercore.Txlease) error { return nil } diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index da4fdefac9..a38ba1462e 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -633,6 +633,7 @@ Global fields are fields that are common to all the transactions in the group. I | 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | | 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. | | 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. | +| 17 | GenesisHash | [32]byte | v10 | The Genesis Hash for the network. | **Asset Fields** diff --git a/data/transactions/logic/TEAL_opcodes_v10.md b/data/transactions/logic/TEAL_opcodes_v10.md index 7df81c33a8..81d742fbd4 100644 --- a/data/transactions/logic/TEAL_opcodes_v10.md +++ b/data/transactions/logic/TEAL_opcodes_v10.md @@ -461,6 +461,7 @@ Fields | 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | | 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. | | 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. | +| 17 | GenesisHash | [32]byte | v10 | The Genesis Hash for the network. | ## gtxn diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 4fdcaae615..0963ee1486 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -1686,17 +1686,19 @@ txn NumApprovalProgramPages txna ApprovalProgramPages 0 txn NumClearStateProgramPages txna ClearStateProgramPages 0 +pushint 1 +block BlkTimestamp +pushint 1 +block BlkSeed global AssetCreateMinBalance global AssetOptInMinBalance +global GenesisHash `, AssemblerMaxVersion) - for _, globalField := range GlobalFieldNames { - if !strings.Contains(text, globalField) { - t.Errorf("TestAssembleDisassemble missing field global %v", globalField) - } - } - for _, txnField := range TxnFieldNames { - if !strings.Contains(text, txnField) { - t.Errorf("TestAssembleDisassemble missing field txn %v", txnField) + for _, names := range [][]string{GlobalFieldNames[:], TxnFieldNames[:], blockFieldNames[:]} { + for _, f := range names { + if !strings.Contains(text, f) { + t.Errorf("TestAssembleDisassemble missing field %v", f) + } } } ops := testProg(t, text, AssemblerMaxVersion) diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 0e1faec0de..883eddcec4 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -200,10 +200,12 @@ func computeMinAvmVersion(group []transactions.SignedTxnWithAD) uint64 { // "stateless" for signature purposes. type LedgerForSignature interface { BlockHdr(basics.Round) (bookkeeping.BlockHeader, error) + GenesisHash() crypto.Digest } -// NoHeaderLedger is intended for debugging situations in which it is reasonable -// to preclude the use of `block` and `txn LastValidTime` +// NoHeaderLedger is intended for debugging TEAL in isolation(no real ledger) in +// which it is reasonable to preclude the use of `block`, `txn +// LastValidTime`. Also `global GenesisHash` is just a static value. type NoHeaderLedger struct { } @@ -212,6 +214,16 @@ func (NoHeaderLedger) BlockHdr(basics.Round) (bookkeeping.BlockHeader, error) { return bookkeeping.BlockHeader{}, fmt.Errorf("no block header access") } +// GenesisHash returns a fixed value +func (NoHeaderLedger) GenesisHash() crypto.Digest { + return crypto.Digest{ + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + } +} + // LedgerForLogic represents ledger API for Stateful TEAL program type LedgerForLogic interface { AccountData(addr basics.Address) (ledgercore.AccountData, error) @@ -3610,8 +3622,11 @@ func (cx *EvalContext) globalFieldToValue(fs globalFieldSpec) (sv stackValue, er sv.Uint = cx.Proto.MinBalance case AssetOptInMinBalance: sv.Uint = cx.Proto.MinBalance + case GenesisHash: + gh := cx.SigLedger.GenesisHash() + sv.Bytes = gh[:] default: - err = fmt.Errorf("invalid global field %d", fs.field) + return sv, fmt.Errorf("invalid global field %s", fs.field) } if fs.ftype.AVMType != sv.avmType() { @@ -5587,7 +5602,7 @@ func opBlock(cx *EvalContext) error { cx.Stack[last].Uint = uint64(hdr.TimeStamp) return nil default: - return fmt.Errorf("invalid block field %d", fs.field) + return fmt.Errorf("invalid block field %s", fs.field) } } diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index 06fee09c13..4682732fb5 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -575,6 +575,37 @@ func TestBadField(t *testing.T) { TestAppBytes(t, ops.Program, ep, "invalid itxn_field FirstValid") } +// TestInnerValidity logs fv and lv fields that are handled oddly (valid +// rounds are copied) so we can check if they are correct. +func TestInnerValidity(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + ep, tx, ledger := MakeSampleEnv() + tx.GenesisHash = crypto.Digest{0x01, 0x02, 0x03} + logger := TestProg(t, ` +txn FirstValid; itob; log; +txn LastValid; itob; log; +int 1`, AssemblerMaxVersion) + ledger.NewApp(tx.Receiver, 222, basics.AppParams{ + ApprovalProgram: logger.Program, + }) + + ledger.NewAccount(appAddr(888), 50_000) + tx.ForeignApps = []basics.AppIndex{basics.AppIndex(222)} + TestApp(t, ` +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit +itxn Logs 0; btoi; txn FirstValid; ==; assert +itxn Logs 1; btoi; txn LastValid; ==; assert +itxn FirstValid; txn FirstValid; ==; assert +itxn LastValid; txn LastValid; ==; assert +int 1 +`, ep) + +} + func TestNumInnerShallow(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 436643e4c2..d25851be0d 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -3435,6 +3435,14 @@ func TestLatestTimestamp(t *testing.T) { testApp(t, source, ep) } +func TestGenHash(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + ep, _, _ := makeSampleEnv() + source := fmt.Sprintf("global GenesisHash; byte 0x%s; ==", hex.EncodeToString(testGenHash[:])) + testApp(t, source, ep) +} + func TestBlockSeed(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -3465,7 +3473,7 @@ func TestBlockSeed(t *testing.T) { testApp(t, "int 4294967310; int 1502; -; block BlkSeed; len; int 32; ==", ep, "not available") // 1501 back from lv is not - // A little silly, as it only tests the test ledger: ensure samenes and differentness + // A little silly, as it only tests the test ledger: ensure sameness and differentness testApp(t, "int 0xfffffff0; block BlkSeed; int 0xfffffff0; block BlkSeed; ==", ep) testApp(t, "int 0xfffffff0; block BlkSeed; int 0xfffffff1; block BlkSeed; !=", ep) diff --git a/data/transactions/logic/fields.go b/data/transactions/logic/fields.go index bb5c2179e9..060516d65f 100644 --- a/data/transactions/logic/fields.go +++ b/data/transactions/logic/fields.go @@ -535,6 +535,9 @@ const ( // AssetOptInMinBalance is the additional minimum balance required to opt in to an asset AssetOptInMinBalance + // GenesisHash is the genesis hash for the network + GenesisHash + invalidGlobalField // compile-time constant for number of fields ) @@ -599,6 +602,7 @@ var globalFieldSpecs = [...]globalFieldSpec{ "The additional minimum balance required to create (and opt-in to) an asset."}, {AssetOptInMinBalance, StackUint64, modeAny, 10, "The additional minimum balance required to opt-in to an asset."}, + {GenesisHash, StackBytes32, modeAny, 10, "The Genesis Hash for the network."}, } func globalFieldSpecByField(f GlobalField) (globalFieldSpec, bool) { @@ -961,6 +965,7 @@ const ( BlkSeed BlockField = iota // BlkTimestamp is the Block's timestamp, seconds from epoch BlkTimestamp + invalidBlockField // compile-time constant for number of fields ) diff --git a/data/transactions/logic/fields_string.go b/data/transactions/logic/fields_string.go index 7d3c2b42f2..37bfeb9bcc 100644 --- a/data/transactions/logic/fields_string.go +++ b/data/transactions/logic/fields_string.go @@ -110,12 +110,13 @@ func _() { _ = x[CallerApplicationAddress-14] _ = x[AssetCreateMinBalance-15] _ = x[AssetOptInMinBalance-16] - _ = x[invalidGlobalField-17] + _ = x[GenesisHash-17] + _ = x[invalidGlobalField-18] } -const _GlobalField_name = "MinTxnFeeMinBalanceMaxTxnLifeZeroAddressGroupSizeLogicSigVersionRoundLatestTimestampCurrentApplicationIDCreatorAddressCurrentApplicationAddressGroupIDOpcodeBudgetCallerApplicationIDCallerApplicationAddressAssetCreateMinBalanceAssetOptInMinBalanceinvalidGlobalField" +const _GlobalField_name = "MinTxnFeeMinBalanceMaxTxnLifeZeroAddressGroupSizeLogicSigVersionRoundLatestTimestampCurrentApplicationIDCreatorAddressCurrentApplicationAddressGroupIDOpcodeBudgetCallerApplicationIDCallerApplicationAddressAssetCreateMinBalanceAssetOptInMinBalanceGenesisHashinvalidGlobalField" -var _GlobalField_index = [...]uint16{0, 9, 19, 29, 40, 49, 64, 69, 84, 104, 118, 143, 150, 162, 181, 205, 226, 246, 264} +var _GlobalField_index = [...]uint16{0, 9, 19, 29, 40, 49, 64, 69, 84, 104, 118, 143, 150, 162, 181, 205, 226, 246, 257, 275} func (i GlobalField) String() string { if i >= GlobalField(len(_GlobalField_index)-1) { diff --git a/data/transactions/logic/fields_test.go b/data/transactions/logic/fields_test.go index f4736f6214..2fd432956a 100644 --- a/data/transactions/logic/fields_test.go +++ b/data/transactions/logic/fields_test.go @@ -112,6 +112,19 @@ func TestTxnFieldVersions(t *testing.T) { asmError = "...txna opcode was introduced in ..." txnaMode = true } + + // tack on a type check, and return a value (`int` gets compiled + // differently in different versions, so use `txn FirstValid` to get + // a positive integer) + switch fs.ftype.AVMType { + case avmUint64: // ensure the return type is uint64 by using ! + text += "; !; pop; txn FirstValid" + case avmBytes: // ensure the return type is bytes by using len + text += "; len; pop; txn FirstValid" + case avmAny: + text += "; pop; txn FirstValid" + } + // check assembler fails if version before introduction testLine(t, text, assemblerNoVersion, asmError) for v := uint64(0); v < fs.version; v++ { @@ -124,6 +137,18 @@ func TestTxnFieldVersions(t *testing.T) { ops := testProg(t, text, AssemblerMaxVersion) + // check success in AssemblerMaxVersion, fs.version + // also ensures the field returns the right type + if !fs.effects { + txgroup[0].Txn.ApprovalProgram = []byte("approve") // not in standard sample txn + txgroup[0].Txn.ClearStateProgram = []byte("clear") + ep := defaultAppParamsWithVersion(AssemblerMaxVersion, txgroup...) + testAppBytes(t, ops.Program, ep) + opsv := testProg(t, text, fs.version) + ep = defaultAppParamsWithVersion(fs.version, txgroup...) + testAppBytes(t, opsv.Program, ep) + } + preVersion := fs.version - 1 ep := defaultSigParamsWithVersion(preVersion, txgroup...) @@ -283,3 +308,36 @@ func TestAcctParamsFieldsVersions(t *testing.T) { } } + +func TestBlockFieldsVersions(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + for _, field := range blockFieldSpecs { + text := fmt.Sprintf("txn FirstValid; int 1; - ; block %s;", field.field) + if field.ftype.AVMType == avmBytes { + text += "global ZeroAddress; concat; len" // use concat to prove we have bytes + } else { + text += "global ZeroAddress; len; +" // use + to prove we have an int + } + + testLogicRange(t, 4, 0, func(t *testing.T, ep *EvalParams, txn *transactions.Transaction, ledger *Ledger) { + v := ep.Proto.LogicSigVersion + if field.version > v { + // check assembler fails if version before introduction + testProg(t, text, v, exp(1, "...was introduced in...")) + ops := testProg(t, text, field.version) // assemble in the future + ops.Program[0] = byte(v) // but set version back to before intro + if v < randomnessVersion { + testAppBytes(t, ops.Program, ep, "illegal opcode", "illegal opcode") + } else { + testAppBytes(t, ops.Program, ep, "invalid block field") + } + } else { + testProg(t, text, v) + testApp(t, text, ep) + } + }) + + } +} diff --git a/data/transactions/logic/langspec_v10.json b/data/transactions/logic/langspec_v10.json index affe46601e..2141e8fe0f 100644 --- a/data/transactions/logic/langspec_v10.json +++ b/data/transactions/logic/langspec_v10.json @@ -1196,7 +1196,8 @@ "CallerApplicationID", "CallerApplicationAddress", "AssetCreateMinBalance", - "AssetOptInMinBalance" + "AssetOptInMinBalance", + "GenesisHash" ], "ArgEnumTypes": [ "uint64", @@ -1215,7 +1216,8 @@ "uint64", "address", "uint64", - "uint64" + "uint64", + "[32]byte" ], "DocCost": "1", "Doc": "global field F", diff --git a/data/transactions/logic/ledger_test.go b/data/transactions/logic/ledger_test.go index a111eec131..a575c493dd 100644 --- a/data/transactions/logic/ledger_test.go +++ b/data/transactions/logic/ledger_test.go @@ -36,6 +36,7 @@ import ( "math" "math/rand" + "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/committee" @@ -607,6 +608,13 @@ func (l *Ledger) AppParams(appID basics.AppIndex) (basics.AppParams, basics.Addr return basics.AppParams{}, basics.Address{}, fmt.Errorf("no app %d", appID) } +var testGenHash = crypto.Digest{0x03, 0x02, 0x03} + +// GenesisHash returns a phony genesis hash that can be tested against +func (l *Ledger) GenesisHash() crypto.Digest { + return testGenHash +} + func (l *Ledger) move(from basics.Address, to basics.Address, amount uint64) error { fbr, ok := l.balances[from] if !ok { diff --git a/data/transactions/logic/teal.tmLanguage.json b/data/transactions/logic/teal.tmLanguage.json index ef80fd048a..e414922e81 100644 --- a/data/transactions/logic/teal.tmLanguage.json +++ b/data/transactions/logic/teal.tmLanguage.json @@ -112,7 +112,7 @@ }, { "name": "variable.parameter.teal", - "match": "\\b(unknown|pay|keyreg|acfg|axfer|afrz|appl|NoOp|OptIn|CloseOut|ClearState|UpdateApplication|DeleteApplication|Secp256k1|Secp256r1|Sender|Fee|FirstValid|FirstValidTime|LastValid|Note|Lease|Receiver|Amount|CloseRemainderTo|VotePK|SelectionPK|VoteFirst|VoteLast|VoteKeyDilution|Type|TypeEnum|XferAsset|AssetAmount|AssetSender|AssetReceiver|AssetCloseTo|GroupIndex|TxID|ApplicationID|OnCompletion|NumAppArgs|NumAccounts|ApprovalProgram|ClearStateProgram|RekeyTo|ConfigAsset|ConfigAssetTotal|ConfigAssetDecimals|ConfigAssetDefaultFrozen|ConfigAssetUnitName|ConfigAssetName|ConfigAssetURL|ConfigAssetMetadataHash|ConfigAssetManager|ConfigAssetReserve|ConfigAssetFreeze|ConfigAssetClawback|FreezeAsset|FreezeAssetAccount|FreezeAssetFrozen|NumAssets|NumApplications|GlobalNumUint|GlobalNumByteSlice|LocalNumUint|LocalNumByteSlice|ExtraProgramPages|Nonparticipation|NumLogs|CreatedAssetID|CreatedApplicationID|LastLog|StateProofPK|NumApprovalProgramPages|NumClearStateProgramPages|MinTxnFee|MinBalance|MaxTxnLife|ZeroAddress|GroupSize|LogicSigVersion|Round|LatestTimestamp|CurrentApplicationID|CreatorAddress|CurrentApplicationAddress|GroupID|OpcodeBudget|CallerApplicationID|CallerApplicationAddress|AssetCreateMinBalance|AssetOptInMinBalance|ApplicationArgs|Accounts|Assets|Applications|Logs|ApprovalProgramPages|ClearStateProgramPages|URLEncoding|StdEncoding|JSONString|JSONUint64|JSONObject|AssetBalance|AssetFrozen|AssetTotal|AssetDecimals|AssetDefaultFrozen|AssetUnitName|AssetName|AssetURL|AssetMetadataHash|AssetManager|AssetReserve|AssetFreeze|AssetClawback|AssetCreator|AppApprovalProgram|AppClearStateProgram|AppGlobalNumUint|AppGlobalNumByteSlice|AppLocalNumUint|AppLocalNumByteSlice|AppExtraProgramPages|AppCreator|AppAddress|AcctBalance|AcctMinBalance|AcctAuthAddr|AcctTotalNumUint|AcctTotalNumByteSlice|AcctTotalExtraAppPages|AcctTotalAppsCreated|AcctTotalAppsOptedIn|AcctTotalAssetsCreated|AcctTotalAssets|AcctTotalBoxes|AcctTotalBoxBytes|VrfAlgorand|BlkSeed|BlkTimestamp|BN254g1|BN254g2|BLS12_381g1|BLS12_381g2)\\b" + "match": "\\b(unknown|pay|keyreg|acfg|axfer|afrz|appl|NoOp|OptIn|CloseOut|ClearState|UpdateApplication|DeleteApplication|Secp256k1|Secp256r1|Sender|Fee|FirstValid|FirstValidTime|LastValid|Note|Lease|Receiver|Amount|CloseRemainderTo|VotePK|SelectionPK|VoteFirst|VoteLast|VoteKeyDilution|Type|TypeEnum|XferAsset|AssetAmount|AssetSender|AssetReceiver|AssetCloseTo|GroupIndex|TxID|ApplicationID|OnCompletion|NumAppArgs|NumAccounts|ApprovalProgram|ClearStateProgram|RekeyTo|ConfigAsset|ConfigAssetTotal|ConfigAssetDecimals|ConfigAssetDefaultFrozen|ConfigAssetUnitName|ConfigAssetName|ConfigAssetURL|ConfigAssetMetadataHash|ConfigAssetManager|ConfigAssetReserve|ConfigAssetFreeze|ConfigAssetClawback|FreezeAsset|FreezeAssetAccount|FreezeAssetFrozen|NumAssets|NumApplications|GlobalNumUint|GlobalNumByteSlice|LocalNumUint|LocalNumByteSlice|ExtraProgramPages|Nonparticipation|NumLogs|CreatedAssetID|CreatedApplicationID|LastLog|StateProofPK|NumApprovalProgramPages|NumClearStateProgramPages|MinTxnFee|MinBalance|MaxTxnLife|ZeroAddress|GroupSize|LogicSigVersion|Round|LatestTimestamp|CurrentApplicationID|CreatorAddress|CurrentApplicationAddress|GroupID|OpcodeBudget|CallerApplicationID|CallerApplicationAddress|AssetCreateMinBalance|AssetOptInMinBalance|GenesisHash|ApplicationArgs|Accounts|Assets|Applications|Logs|ApprovalProgramPages|ClearStateProgramPages|URLEncoding|StdEncoding|JSONString|JSONUint64|JSONObject|AssetBalance|AssetFrozen|AssetTotal|AssetDecimals|AssetDefaultFrozen|AssetUnitName|AssetName|AssetURL|AssetMetadataHash|AssetManager|AssetReserve|AssetFreeze|AssetClawback|AssetCreator|AppApprovalProgram|AppClearStateProgram|AppGlobalNumUint|AppGlobalNumByteSlice|AppLocalNumUint|AppLocalNumByteSlice|AppExtraProgramPages|AppCreator|AppAddress|AcctBalance|AcctMinBalance|AcctAuthAddr|AcctTotalNumUint|AcctTotalNumByteSlice|AcctTotalExtraAppPages|AcctTotalAppsCreated|AcctTotalAppsOptedIn|AcctTotalAssetsCreated|AcctTotalAssets|AcctTotalBoxes|AcctTotalBoxBytes|VrfAlgorand|BlkSeed|BlkTimestamp|BN254g1|BN254g2|BLS12_381g1|BLS12_381g2)\\b" } ] }, diff --git a/data/transactions/verify/txn_test.go b/data/transactions/verify/txn_test.go index 416c0e4c08..d2061b872a 100644 --- a/data/transactions/verify/txn_test.go +++ b/data/transactions/verify/txn_test.go @@ -78,6 +78,9 @@ func (d *DummyLedgerForSignature) BlockHdr(rnd basics.Round) (blk bookkeeping.Bl } return createDummyBlockHeader(), nil } +func (d *DummyLedgerForSignature) GenesisHash() crypto.Digest { + return crypto.Digest{} +} func (d *DummyLedgerForSignature) Latest() basics.Round { return 0 } diff --git a/ledger/eval/appcow_test.go b/ledger/eval/appcow_test.go index 2c46d02c09..a4c8d22c67 100644 --- a/ledger/eval/appcow_test.go +++ b/ledger/eval/appcow_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/require" "github.com/algorand/go-algorand/config" + "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/transactions" @@ -99,8 +100,8 @@ func (ml *emptyLedger) BlockHdr(rnd basics.Round) (bookkeeping.BlockHeader, erro return bookkeeping.BlockHeader{}, nil } -func (ml *emptyLedger) blockHdrCached(rnd basics.Round) (bookkeeping.BlockHeader, error) { - return bookkeeping.BlockHeader{}, nil +func (ml *emptyLedger) GenesisHash() crypto.Digest { + return crypto.Digest{} } func (ml *emptyLedger) GetStateProofNextRound() basics.Round { diff --git a/ledger/eval/cow.go b/ledger/eval/cow.go index d797a4a560..f3e6b3d049 100644 --- a/ledger/eval/cow.go +++ b/ledger/eval/cow.go @@ -22,6 +22,7 @@ import ( "sync" "github.com/algorand/go-algorand/config" + "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/transactions" @@ -65,6 +66,7 @@ type roundCowParent interface { getKey(addr basics.Address, aidx basics.AppIndex, global bool, key string, accountIdx uint64) (basics.TealValue, bool, error) kvGet(key string) ([]byte, bool, error) GetStateProofVerificationContext(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationContext, error) + GenesisHash() crypto.Digest } // When adding new fields make sure to clear them in the roundCowState.recycle() as well to avoid dirty state @@ -245,6 +247,10 @@ func (cb *roundCowState) BlockHdr(r basics.Round) (bookkeeping.BlockHeader, erro return cb.lookupParent.BlockHdr(r) } +func (cb *roundCowState) GenesisHash() crypto.Digest { + return cb.lookupParent.GenesisHash() +} + func (cb *roundCowState) GetStateProofVerificationContext(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationContext, error) { return cb.lookupParent.GetStateProofVerificationContext(stateProofLastAttestedRound) } diff --git a/ledger/eval/cow_test.go b/ledger/eval/cow_test.go index 225b037997..5e1253adce 100644 --- a/ledger/eval/cow_test.go +++ b/ledger/eval/cow_test.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "github.com/algorand/go-algorand/config" + "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/stateproofmsg" @@ -103,8 +104,8 @@ func (ml *mockLedger) BlockHdr(rnd basics.Round) (bookkeeping.BlockHeader, error return bookkeeping.BlockHeader{}, errors.New("requested blockheader not found") } -func (ml *mockLedger) blockHdrCached(rnd basics.Round) (bookkeeping.BlockHeader, error) { - return ml.BlockHdr(rnd) +func (ml *mockLedger) GenesisHash() crypto.Digest { + panic("GenesisHash unused by tests") } func (ml *mockLedger) GetStateProofVerificationContext(rnd basics.Round) (*ledgercore.StateProofVerificationContext, error) { diff --git a/ledger/eval/eval.go b/ledger/eval/eval.go index 58f7fc8a4f..714e6bddf4 100644 --- a/ledger/eval/eval.go +++ b/ledger/eval/eval.go @@ -40,6 +40,7 @@ import ( // LedgerForCowBase represents subset of Ledger functionality needed for cow business type LedgerForCowBase interface { BlockHdr(basics.Round) (bookkeeping.BlockHeader, error) + GenesisHash() crypto.Digest CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledgercore.Txlease) error LookupWithoutRewards(basics.Round, basics.Address) (ledgercore.AccountData, basics.Round, error) LookupAsset(basics.Round, basics.Address, basics.AssetIndex) (ledgercore.AssetResource, error) @@ -337,6 +338,10 @@ func (x *roundCowBase) BlockHdr(r basics.Round) (bookkeeping.BlockHeader, error) return x.l.BlockHdr(r) } +func (x *roundCowBase) GenesisHash() crypto.Digest { + return x.l.GenesisHash() +} + func (x *roundCowBase) GetStateProofVerificationContext(stateProofLastAttestedRound basics.Round) (*ledgercore.StateProofVerificationContext, error) { return x.l.GetStateProofVerificationContext(stateProofLastAttestedRound) } diff --git a/ledger/eval/eval_test.go b/ledger/eval/eval_test.go index b916558314..93a2afd2da 100644 --- a/ledger/eval/eval_test.go +++ b/ledger/eval/eval_test.go @@ -1037,6 +1037,10 @@ func (l *testCowBaseLedger) BlockHdr(basics.Round) (bookkeeping.BlockHeader, err return bookkeeping.BlockHeader{}, errors.New("not implemented") } +func (l *testCowBaseLedger) GenesisHash() crypto.Digest { + panic("not implemented") +} + func (l *testCowBaseLedger) CheckDup(config.ConsensusParams, basics.Round, basics.Round, basics.Round, transactions.Txid, ledgercore.Txlease) error { return errors.New("not implemented") }