diff --git a/ledger/acctonline_expired_test.go b/ledger/acctonline_expired_test.go index 3e46c41ecb..90ebc931a1 100644 --- a/ledger/acctonline_expired_test.go +++ b/ledger/acctonline_expired_test.go @@ -25,6 +25,7 @@ import ( "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/crypto/merklesignature" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/txntest" @@ -320,6 +321,7 @@ func (m *doubleLedgerAcctModel) goOnline(addr basics.Address, firstvalid, lastva // meaningless non-zero voting data VotePK: crypto.OneTimeSignatureVerifier(addr), SelectionPK: crypto.VRFVerifier(addr), + StateProofPK: merklesignature.Commitment{1}, VoteKeyDilution: 1024, }) m.accts[addr] = m.ops.Sub(m.accts[addr], basics.MicroAlgos{Raw: minFee}) diff --git a/ledger/apptxn_test.go b/ledger/apptxn_test.go index 8f8047feaf..ff80358df6 100644 --- a/ledger/apptxn_test.go +++ b/ledger/apptxn_test.go @@ -62,19 +62,24 @@ func TestPayAction(t *testing.T) { // We're going to test some payout effects here too, so that we have an inner transaction example. proposer := basics.Address{0x01, 0x02, 0x03} + stateProofPK := merklesignature.Commitment{0x03} + if ver < 31 { // no state proof support + stateProofPK = merklesignature.Commitment{} + } dl.txns(&txntest.Txn{ Type: "pay", Sender: addrs[7], Receiver: proposer, Amount: 1_000_000 * 1_000_000, // 1 million algos is surely an eligible amount }, &txntest.Txn{ - Type: "keyreg", - Sender: proposer, - Fee: 3_000_000, - VotePK: crypto.OneTimeSignatureVerifier{0x01}, - SelectionPK: crypto.VRFVerifier{0x02}, - StateProofPK: merklesignature.Commitment{0x03}, - VoteFirst: 1, VoteLast: 1000, + Type: "keyreg", + Sender: proposer, + Fee: 3_000_000, + VotePK: crypto.OneTimeSignatureVerifier{0x01}, + SelectionPK: crypto.VRFVerifier{0x02}, + VoteKeyDilution: 1000, + StateProofPK: stateProofPK, + VoteFirst: 1, VoteLast: 1000, }) payout1 := txntest.Txn{ @@ -1818,6 +1823,9 @@ func TestSelfCheckHoldingNewApp(t *testing.T) { ForeignAssets: []basics.AssetIndex{assetID}, } selfcheck.ApplicationID = dl.txn(&selfcheck).ApplicationID + // remove programs to just call the app + selfcheck.ApprovalProgram = nil + selfcheck.ClearStateProgram = nil dl.txn(&selfcheck) @@ -1867,6 +1875,9 @@ func TestCheckHoldingNewApp(t *testing.T) { ForeignAssets: []basics.AssetIndex{assetID}, } check.ApplicationID = dl.txn(&check).ApplyData.ApplicationID + // remove the programs to just call the app + check.ApprovalProgram = nil + check.ClearStateProgram = nil create := txntest.Txn{ Type: "appl", @@ -3703,8 +3714,10 @@ func TestUnfundedSenders(t *testing.T) { // v34 enabled UnfundedSenders var problem string - if ver < 34 { - // In the old days, balances.Move would try to increase the rewardsState on the unfunded account + // In the old days, balances.Move would try to increase the rewardsState on the unfunded account + if ver < 28 { + problem = "transaction had fee 0, which is less than the minimum 1000" + } else if ver < 34 { problem = "balance 0 below min" } for i, e := range ephemeral { diff --git a/ledger/boxtxn_test.go b/ledger/boxtxn_test.go index 1d52e3c888..ba8f71b65b 100644 --- a/ledger/boxtxn_test.go +++ b/ledger/boxtxn_test.go @@ -588,10 +588,33 @@ func TestBoxIOBudgets(t *testing.T) { dl.txn(call.Args("check", "x", "\x00"), "box read budget") // Give a budget over 32768, confirm failure anyway - empties := [32]transactions.BoxRef{} - // These tests skip WellFormed, so the huge Boxes is ok - call.Boxes = append(call.Boxes, empties[:]...) - dl.txn(call.Args("create", "x", "\x80\x01"), "box size too large") // 32769 + // Use a transaction group with 5 txns, each with 8 box refs (except the last one) + // to accumulate enough box references (33 total) for the quota test + txns := make([]*txntest.Txn, 5) + for i := 0; i < 4; i++ { + // Create 8 valid box references to the existing box "x" + boxes := make([]transactions.BoxRef, 8) + for j := 0; j < 8; j++ { + boxes[j] = transactions.BoxRef{Index: 0, Name: []byte("x")} + } + txns[i] = &txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: appID, + Boxes: boxes, + ApplicationArgs: [][]byte{[]byte("check"), []byte("x"), []byte("\x00")}, // box contains zeros + Note: []byte{byte(i)}, // vary the note to make txns unique + } + } + // Last transaction tries to create a box > 32K, which should fail even with enough quota + txns[4] = &txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApplicationID: appID, + Boxes: []transactions.BoxRef{{Index: 0, Name: []byte("y")}}, // 1 ref, total 33 refs in group + ApplicationArgs: [][]byte{[]byte("create"), []byte("y"), []byte("\x80\x01")}, // 32769 bytes + } + dl.txgroup("box size too large", txns...) }) } @@ -718,8 +741,26 @@ func TestNewAppBoxCreate(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() + t.Run("current", func(t *testing.T) { testNewAppBoxCreate(t, 0) }) + t.Run("tealv9", func(t *testing.T) { testNewAppBoxCreate(t, 9) }) + t.Run("tealv12", func(t *testing.T) { testNewAppBoxCreate(t, 12) }) +} + +func testNewAppBoxCreate(t *testing.T, requestedTealVersion int) { genBalances, addrs, _ := ledgertesting.NewTestGenesis() ledgertesting.TestConsensusRange(t, boxVersion, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + proto := config.Consensus[cv] + + tealVersion := requestedTealVersion + if tealVersion == 0 { + tealVersion = int(proto.LogicSigVersion) + } + + // Skip for combinations of tealVersion and cv that aren't possible + if uint64(tealVersion) > proto.LogicSigVersion { + t.Skipf("TEAL v%d not available in %s (LogicSigVersion=%d)", tealVersion, cv, proto.LogicSigVersion) + } + dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() @@ -753,8 +794,11 @@ func TestNewAppBoxCreate(t *testing.T) { boxPut := "txn ApplicationArgs 0; int 24; bzero; box_put; int 1;" for _, createSrc := range []string{boxCreate, boxPut} { + // createSrcVer is the versioned source for the current test's TEAL version + createSrcVer := fmt.Sprintf("#pragma version %d\n%s", tealVersion, createSrc) + // doubleSrc tries to create TWO boxes. The second is always named by ApplicationArgs 1 - doubleSrc := createSrc + `txn ApplicationArgs 1; int 24; box_create; pop;` // return result of FIRST box_create + doubleSrc := createSrcVer + `txn ApplicationArgs 1; int 24; box_create; pop;` // return result of FIRST box_create // need to call one inner txn, and have have mbr for itself and inner created app passID := dl.fundedApp(addrs[0], 201_000, passThruCreator) // Will be used to show inners have same power @@ -769,19 +813,19 @@ func TestNewAppBoxCreate(t *testing.T) { // Try to create it. It will fail because there's no box ref. (does not increment txncounter) dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}}, "invalid Box reference 0x01") // 2a. Create it with a box ref of the predicted appID dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, ForeignApps: []basics.AppIndex{passID + testTxns + 2}, Boxes: []transactions.BoxRef{{Index: 1, Name: []byte{0x01}}}}) // 2a. Create it with a box ref of the predicted appID (Access list) - if ver >= accessVersion { + if proto.MaxAppAccess > 0 { dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, Access: []transactions.ResourceRef{ {App: passID + testTxns + 3}, {Box: transactions.BoxRef{Index: 1, Name: []byte{0x01}}}}}) @@ -789,13 +833,13 @@ func TestNewAppBoxCreate(t *testing.T) { // 2b. Create it with a box ref of 0, which means "this app" dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, Boxes: []transactions.BoxRef{{Index: 0, Name: []byte{0x01}}}}) // 2b. Create it with a box ref of 0, which means "this app" (Access List) - if ver >= accessVersion { + if proto.MaxAppAccess > 0 { dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, Access: []transactions.ResourceRef{ {Box: transactions.BoxRef{Index: 0, Name: []byte{0x01}}}}}) } @@ -822,12 +866,12 @@ func TestNewAppBoxCreate(t *testing.T) { if ver >= newAppCreateVersion { // 2c. Create it with an empty box ref dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, Boxes: []transactions.BoxRef{{}}}) // 2c. Create it with an empty box ref dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, Access: []transactions.ResourceRef{{Box: transactions.BoxRef{}}}}) // but you can't do a second create @@ -861,7 +905,7 @@ func TestNewAppBoxCreate(t *testing.T) { } else { // 2c. Doesn't work yet until `newAppCreateVersion` dl.txn(&txntest.Txn{Type: "appl", Sender: addrs[0], - ApprovalProgram: createSrc, ApplicationArgs: [][]byte{{0x01}}, + ApprovalProgram: createSrcVer, ApplicationArgs: [][]byte{{0x01}}, Boxes: []transactions.BoxRef{{}}}, "invalid Box reference 0x01") } diff --git a/ledger/double_test.go b/ledger/double_test.go index 13f5b0f552..151f1dda2a 100644 --- a/ledger/double_test.go +++ b/ledger/double_test.go @@ -72,6 +72,10 @@ func (dl *DoubleLedger) beginBlock() *eval.BlockEvaluator { return dl.eval } +// txn will add a transaction to the current block. If no block is +// currently being built, it will start one, and end it after the +// transaction is added. If a problem is specified, it will be +// expected to fail, and the block will not be ended. func (dl *DoubleLedger) txn(tx *txntest.Txn, problem ...string) (stib *transactions.SignedTxnInBlock) { dl.t.Helper() if dl.eval == nil { diff --git a/ledger/eval/eval.go b/ledger/eval/eval.go index a0f64a9438..395737a689 100644 --- a/ledger/eval/eval.go +++ b/ledger/eval/eval.go @@ -1184,6 +1184,12 @@ func (eval *BlockEvaluator) transaction(txn transactions.SignedTxn, evalParams * return err } + err = txn.Txn.WellFormed(eval.specials, eval.proto) + if err != nil { + txnErr := ledgercore.TxnNotWellFormedError(fmt.Sprintf("transaction %v: malformed: %v", txn.ID(), err)) + return &txnErr + } + // Transaction already in the ledger? err = cow.checkDup(txn.Txn.FirstValid, txn.Txn.LastValid, txid, ledgercore.Txlease{Sender: txn.Txn.Sender, Lease: txn.Txn.Lease}) if err != nil { diff --git a/ledger/eval/eval_test.go b/ledger/eval/eval_test.go index 0f176fb41f..d1ca474c65 100644 --- a/ledger/eval/eval_test.go +++ b/ledger/eval/eval_test.go @@ -1410,6 +1410,7 @@ func TestAbsenteeChecks(t *testing.T) { Header: transactions.Header{ Sender: addrs[i], Fee: minFee, + FirstValid: blkEval.Round().SubSaturate(1000), LastValid: blkEval.Round(), GenesisHash: l.GenesisHash(), }, diff --git a/ledger/eval_simple_test.go b/ledger/eval_simple_test.go index dfe051b578..90372dbd04 100644 --- a/ledger/eval_simple_test.go +++ b/ledger/eval_simple_test.go @@ -223,10 +223,17 @@ func TestPayoutFees(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - // Lots of balance checks that would be messed up by rewards - genBalances, addrs, _ := ledgertesting.NewTestGenesis(ledgertesting.TurnOffRewards) payoutsBegin := 40 ledgertesting.TestConsensusRange(t, payoutsBegin-1, 0, func(t *testing.T, ver int, cv protocol.ConsensusVersion, cfg config.Local) { + // Lots of balance checks that would be messed up by rewards + opts := []ledgertesting.TestGenesisOption{ledgertesting.TurnOffRewards} + // When payouts are enabled, set a starting feesink balance to ensure it drains by the end of the test + if ver >= payoutsBegin { + opts = append(opts, ledgertesting.InitialFeeSinkBalance(18_998_000)) + } + + // Create genesis with the appropriate options + genBalances, addrs, _ := ledgertesting.NewTestGenesis(opts...) dl := NewDoubleLedger(t, genBalances, cv, cfg) defer dl.Close() @@ -241,13 +248,14 @@ func TestPayoutFees(t *testing.T) { require.False(t, prp.IncentiveEligible) dl.txn(&txntest.Txn{ - Type: "keyreg", - Sender: proposer, - Fee: eFee, - VotePK: crypto.OneTimeSignatureVerifier{0x01}, - SelectionPK: crypto.VRFVerifier{0x02}, - StateProofPK: merklesignature.Commitment{0x03}, - VoteFirst: 1, VoteLast: 1000, + Type: "keyreg", + Sender: proposer, + Fee: eFee, + VotePK: crypto.OneTimeSignatureVerifier{0x01}, + SelectionPK: crypto.VRFVerifier{0x02}, + StateProofPK: merklesignature.Commitment{0x03}, + VoteKeyDilution: 1000, + VoteFirst: 1, VoteLast: 1000, }) prp = lookup(dl.t, dl.generator, proposer) @@ -266,7 +274,7 @@ func TestPayoutFees(t *testing.T) { Receiver: addrs[2], Amount: 100000, } - dl.txns(&pay, pay.Args("again")) + dl.txns(&pay, pay.Noted("again")) vb := dl.endBlock(proposer) postsink := micros(dl.t, dl.generator, genBalances.FeeSink) @@ -318,13 +326,9 @@ func TestPayoutFees(t *testing.T) { // Get the feesink down low, then drain it by proposing. feesink := vb.Block().FeeSink - data := lookup(t, dl.generator, feesink) - dl.txn(&txntest.Txn{ - Type: "pay", - Sender: feesink, - Receiver: addrs[1], - Amount: data.MicroAlgos.Raw - 12_000_000, - }) + dl.beginBlock() + dl.endBlock() + dl.beginBlock() dl.endBlock(proposer) require.EqualValues(t, micros(t, dl.generator, feesink), 2_000_000) @@ -378,11 +382,12 @@ func TestIncentiveEligible(t *testing.T) { // Keyreg to get online with various fees. Sufficient fee gets `smallest` eligible keyreg := txntest.Txn{ - Type: "keyreg", - VotePK: crypto.OneTimeSignatureVerifier{0x01}, - SelectionPK: crypto.VRFVerifier{0x02}, - StateProofPK: merklesignature.Commitment{0x03}, - VoteFirst: 1, VoteLast: 1000, + Type: "keyreg", + VotePK: crypto.OneTimeSignatureVerifier{0x01}, + SelectionPK: crypto.VRFVerifier{0x02}, + StateProofPK: merklesignature.Commitment{0x03}, + VoteKeyDilution: 1000, + VoteFirst: 1, VoteLast: 1000, } tooSmallKR := keyreg tooSmallKR.Sender = tooSmall @@ -485,11 +490,15 @@ func TestAbsentTracking(t *testing.T) { // have addrs[1] go online explicitly, which makes it eligible for suspension. // use a large fee, so we can see IncentiveEligible change vb := dl.fullBlock(&txntest.Txn{ // #2 - Type: "keyreg", - Fee: 10_000_000, - Sender: addrs[1], - VotePK: [32]byte{1}, - SelectionPK: [32]byte{1}, + Type: "keyreg", + Fee: 10_000_000, + Sender: addrs[1], + VotePK: [32]byte{1}, + SelectionPK: [32]byte{1}, + VoteKeyDilution: 1, + StateProofPK: merklesignature.Commitment{1}, + VoteFirst: 1, + VoteLast: 1000, }) addr1Keyreg := vb.Block().Round() require.EqualValues(t, 2, addr1Keyreg) // sanity check @@ -558,10 +567,12 @@ func TestAbsentTracking(t *testing.T) { // ONLINE keyreg without extra fee vb = dl.fullBlock(&txntest.Txn{ - Type: "keyreg", - Sender: addrs[2], - VotePK: [32]byte{1}, - SelectionPK: [32]byte{1}, + Type: "keyreg", + Sender: addrs[2], + VotePK: [32]byte{1}, + SelectionPK: [32]byte{1}, + VoteKeyDilution: 1, + StateProofPK: merklesignature.Commitment{1}, }) // #10 printAbsent(vb) // online totals have grown, addr[2] was added @@ -583,11 +594,13 @@ func TestAbsentTracking(t *testing.T) { // ONLINE keyreg with extra fee vb = dl.fullBlock(&txntest.Txn{ - Type: "keyreg", - Fee: 2_000_000, - Sender: addrs[2], - VotePK: [32]byte{1}, - SelectionPK: [32]byte{1}, + Type: "keyreg", + Fee: 2_000_000, + Sender: addrs[2], + VotePK: [32]byte{1}, + SelectionPK: [32]byte{1}, + VoteKeyDilution: 1, + StateProofPK: merklesignature.Commitment{1}, }) // #14 printAbsent(vb) addr2Eligible := vb.Block().Round() @@ -737,11 +750,13 @@ func TestAbsenteeChallenges(t *testing.T) { Receiver: guy, Amount: 10_000_000, }, &txntest.Txn{ - Type: "keyreg", - Fee: 5_000_000, // enough to be incentive eligible - Sender: guy, - VotePK: [32]byte{byte(i + 1)}, - SelectionPK: [32]byte{byte(i + 1)}, + Type: "keyreg", + Fee: 5_000_000, // enough to be incentive eligible + Sender: guy, + VotePK: [32]byte{byte(i + 1)}, + SelectionPK: [32]byte{byte(i + 1)}, + VoteKeyDilution: uint64(i + 1), + StateProofPK: merklesignature.Commitment{byte(i + 1)}, }) acct := lookup(t, dl.generator, guy) require.Equal(t, basics.Online, acct.Status) @@ -768,10 +783,12 @@ func TestAbsenteeChallenges(t *testing.T) { // regguy keyregs before he's caught, which is a heartbeat, he stays on as well vb := dl.fullBlock(&txntest.Txn{ - Type: "keyreg", // Does not pay extra fee, since he's still eligible - Sender: regguy, - VotePK: [32]byte{1}, - SelectionPK: [32]byte{1}, + Type: "keyreg", // Does not pay extra fee, since he's still eligible + Sender: regguy, + VotePK: [32]byte{1}, + SelectionPK: [32]byte{1}, + VoteKeyDilution: 1, + StateProofPK: merklesignature.Commitment{1}, }) require.Equal(t, basics.Round(1200), vb.Block().Round()) require.Empty(t, vb.Block().AbsentParticipationAccounts) @@ -924,10 +941,12 @@ func TestVoterAccess(t *testing.T) { // have addrs[1] go online, though it won't be visible right away dl.txn(&txntest.Txn{ - Type: "keyreg", - Sender: addrs[1], - VotePK: [32]byte{0xaa}, - SelectionPK: [32]byte{0xbb}, + Type: "keyreg", + Sender: addrs[1], + VotePK: [32]byte{0xaa}, + SelectionPK: [32]byte{0xbb}, + VoteKeyDilution: 1000, + StateProofPK: merklesignature.Commitment{0xcc}, }) one := basics.Address{0xaa, 0x11} @@ -971,10 +990,12 @@ func TestVoterAccess(t *testing.T) { Receiver: addr, Amount: (uint64(i) + 1) * 1_000_000_000, }, &txntest.Txn{ - Type: "keyreg", - Sender: addr, - VotePK: [32]byte{byte(i + 1)}, - SelectionPK: [32]byte{byte(i + 1)}, + Type: "keyreg", + Sender: addr, + VotePK: [32]byte{byte(i + 1)}, + SelectionPK: [32]byte{byte(i + 1)}, + VoteKeyDilution: uint64(1000 + i), + StateProofPK: merklesignature.Commitment{byte(i + 1)}, }) } // they don't have online stake yet diff --git a/ledger/simple_test.go b/ledger/simple_test.go index 0377a29d54..2f846bdc5c 100644 --- a/ledger/simple_test.go +++ b/ledger/simple_test.go @@ -117,7 +117,9 @@ func fillDefaults(t testing.TB, ledger *Ledger, eval *eval.BlockEvaluator, txn * if txn.FirstValid == 0 { txn.FirstValid = eval.Round() } - if txn.Type == protocol.KeyRegistrationTx && txn.VoteFirst == 0 { + if txn.Type == protocol.KeyRegistrationTx && txn.VoteFirst == 0 && + // check this is not an offline txn + (!txn.VotePK.IsEmpty() || !txn.SelectionPK.IsEmpty()) { txn.VoteFirst = eval.Round() } diff --git a/ledger/testing/testGenesis.go b/ledger/testing/testGenesis.go index 69a5bbcc86..353f68b5bd 100644 --- a/ledger/testing/testGenesis.go +++ b/ledger/testing/testGenesis.go @@ -28,6 +28,7 @@ import ( // GenesisCfg provides a configuration object for NewTestGenesis. type GenesisCfg struct { rewardsPoolAmount basics.MicroAlgos + feeSinkAmount basics.MicroAlgos OnlineCount int } @@ -38,6 +39,14 @@ type TestGenesisOption func(*GenesisCfg) // "surprise" balance changes. var TurnOffRewards = func(cfg *GenesisCfg) { cfg.rewardsPoolAmount = basics.MicroAlgos{Raw: 100_000} } +// InitialFeeSinkBalance sets the initial balance of the fee sink to a specific value. +// This is useful for tests that need precise control over the fee sink balance. +func InitialFeeSinkBalance(microAlgos uint64) TestGenesisOption { + return func(cfg *GenesisCfg) { + cfg.feeSinkAmount = basics.MicroAlgos{Raw: microAlgos} + } +} + // NewTestGenesis creates a bunch of accounts, splits up 10B algos // between them and the rewardspool and feesink, and gives out the // addresses and secrets it creates to enable tests. For special @@ -88,8 +97,12 @@ func NewTestGenesis(opts ...TestGenesisOption) (bookkeeping.GenesisBalances, []b accts[addrs[i]] = adata } + feeSinkBal := basics.MicroAlgos{Raw: amount} + if cfg.feeSinkAmount.Raw > 0 { + feeSinkBal = cfg.feeSinkAmount + } accts[sink] = basics.AccountData{ - MicroAlgos: basics.MicroAlgos{Raw: amount}, + MicroAlgos: feeSinkBal, Status: basics.NotParticipating, }