Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AVM: Add global GenesisHash #5858

Merged
merged 3 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/tealdbg/localLedger.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@
return bookkeeping.BlockHeader{}, nil
}

func (l *localLedger) GenesisHash() crypto.Digest {
return crypto.Digest{}

Check warning on line 285 in cmd/tealdbg/localLedger.go

View check run for this annotation

Codecov / codecov/patch

cmd/tealdbg/localLedger.go#L284-L285

Added lines #L284 - L285 were not covered by tests
}

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")
}
Expand Down
5 changes: 5 additions & 0 deletions daemon/algod/api/server/v2/dryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down
1 change: 1 addition & 0 deletions data/transactions/logic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
Expand Down
1 change: 1 addition & 0 deletions data/transactions/logic/TEAL_opcodes_v10.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 10 additions & 8 deletions data/transactions/logic/assembler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 19 additions & 4 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,12 @@
// "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 {
}

Expand All @@ -212,6 +214,16 @@
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)
Expand Down Expand Up @@ -3610,8 +3622,11 @@
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)

Check warning on line 3629 in data/transactions/logic/eval.go

View check run for this annotation

Codecov / codecov/patch

data/transactions/logic/eval.go#L3629

Added line #L3629 was not covered by tests
}

if fs.ftype.AVMType != sv.avmType() {
Expand Down Expand Up @@ -5587,7 +5602,7 @@
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)

Check warning on line 5605 in data/transactions/logic/eval.go

View check run for this annotation

Codecov / codecov/patch

data/transactions/logic/eval.go#L5605

Added line #L5605 was not covered by tests
}
}

Expand Down
29 changes: 29 additions & 0 deletions data/transactions/logic/evalAppTxn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,35 @@ 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
jannotti marked this conversation as resolved.
Show resolved Hide resolved
int 1
`, ep)

}

func TestNumInnerShallow(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()
Expand Down
10 changes: 9 additions & 1 deletion data/transactions/logic/evalStateful_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)

Expand Down
5 changes: 5 additions & 0 deletions data/transactions/logic/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
)

Expand Down
7 changes: 4 additions & 3 deletions data/transactions/logic/fields_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions data/transactions/logic/fields_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand All @@ -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...)

Expand Down Expand Up @@ -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)
}
})

}
}
6 changes: 4 additions & 2 deletions data/transactions/logic/langspec_v10.json
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,8 @@
"CallerApplicationID",
"CallerApplicationAddress",
"AssetCreateMinBalance",
"AssetOptInMinBalance"
"AssetOptInMinBalance",
"GenesisHash"
],
"ArgEnumTypes": [
"uint64",
Expand All @@ -1215,7 +1216,8 @@
"uint64",
"address",
"uint64",
"uint64"
"uint64",
"[32]byte"
],
"DocCost": "1",
"Doc": "global field F",
Expand Down
8 changes: 8 additions & 0 deletions data/transactions/logic/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion data/transactions/logic/teal.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
},
Expand Down
3 changes: 3 additions & 0 deletions data/transactions/verify/txn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
5 changes: 3 additions & 2 deletions ledger/eval/appcow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
jannotti marked this conversation as resolved.
Show resolved Hide resolved
return crypto.Digest{}
}

func (ml *emptyLedger) GetStateProofNextRound() basics.Round {
Expand Down