From c0ba7142fcc761ca8e1491fce6bdce03c0f76312 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Tue, 27 Feb 2024 16:40:50 -0500 Subject: [PATCH 1/8] Fix: Fix indexer sync issue in cucumber tests (#628) --- test/applications_integration_test.go | 36 ++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/test/applications_integration_test.go b/test/applications_integration_test.go index 88a4e6da..02466f86 100644 --- a/test/applications_integration_test.go +++ b/test/applications_integration_test.go @@ -36,6 +36,7 @@ var transientAccount crypto.Account var applicationId uint64 var applicationIds []uint64 var txComposerMethodResults []transaction.ABIMethodResult +var lastTxConfirmedRound uint64 func anAlgodVClientConnectedToPortWithToken(v int, host string, port int, token string) error { var err error @@ -238,10 +239,11 @@ func iSignAndSubmitTheTransactionSavingTheTxidIfThereIsAnErrorItIs(expectedErr s } func iWaitForTheTransactionToBeConfirmed() error { - _, err := transaction.WaitForConfirmation(algodV2client, txid, 1, context.Background()) + res, err := transaction.WaitForConfirmation(algodV2client, txid, 1, context.Background()) if err != nil { return err } + lastTxConfirmedRound = res.ConfirmedRound return nil } @@ -867,8 +869,34 @@ func currentApplicationShouldHaveFollowingBoxes(fromClient, encodedBoxesRaw stri return nil } -func sleptForNMilliSecsForIndexer(n int) error { - time.Sleep(time.Duration(n) * time.Millisecond) +func waitForIndexerToCatchUp() error { + const maxAttempts = 30 + + roundToWaitFor := lastTxConfirmedRound + indexerRound := uint64(0) + attempts := 0 + + for { + res, err := indexerV2client.HealthCheck().Do(context.Background()) + if err != nil { + return err + } + indexerRound = res.Round + if indexerRound >= roundToWaitFor { + // Success + break + } + + // Sleep for 1 second and try again + time.Sleep(time.Second) + attempts++ + + if attempts > maxAttempts { + // Failsafe to prevent infinite loop + return fmt.Errorf("timeout waiting for indexer to catch up to round %d. It is currently on %d", roundToWaitFor, indexerRound) + } + } + return nil } @@ -963,5 +991,5 @@ func ApplicationsContext(s *godog.Suite) { s.Step(`^according to "([^"]*)", the current application should have the following boxes "([^"]*)"\.$`, currentApplicationShouldHaveFollowingBoxes) s.Step(`^according to "([^"]*)", with (\d+) being the parameter that limits results, the current application should have (\d+) boxes\.$`, currentApplicationShouldHaveBoxNum) s.Step(`^according to indexer, with (\d+) being the parameter that limits results, and "([^"]*)" being the parameter that sets the next result, the current application should have the following boxes "([^"]*)"\.$`, indexerSaysCurrentAppShouldHaveTheseBoxes) - s.Step(`^I sleep for (\d+) milliseconds for indexer to digest things down\.$`, sleptForNMilliSecsForIndexer) + s.Step(`^I wait for indexer to catch up to the round where my most recent transaction was confirmed\.$`, waitForIndexerToCatchUp) } From 3be118b003acb02179886c95989ba1de88859f8e Mon Sep 17 00:00:00 2001 From: Gary <982483+gmalouf@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:29:56 -0500 Subject: [PATCH 2/8] Bump go version for builds/workflows to 1.20.14. (#629) --- .circleci/config.yml | 2 +- .github/workflows/reviewdog.yml | 4 ++-- test/docker/Dockerfile | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5fb9a5b9..85d2e3cf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ workflows: name: 'test_go_<< matrix.go_version >>' matrix: parameters: - go_version: ['1.20.5'] + go_version: ['1.20.14'] jobs: test: diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 2f3845da..4cb4b7b5 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -12,7 +12,7 @@ jobs: - name: Install specific golang uses: actions/setup-go@v4.0.1 with: - go-version: '1.20.5' + go-version: '1.20.14' - name: Check format run: test -z `go fmt ./...` - name: Vet @@ -22,7 +22,7 @@ jobs: with: golangci_lint_version: "v1.53.2" golangci_lint_flags: "-c .golangci.yml --allow-parallel-runners" - go_version: "1.20.5" + go_version: "1.20.14" reporter: "github-pr-review" tool_name: "Lint Errors" level: "error" diff --git a/test/docker/Dockerfile b/test/docker/Dockerfile index 610e5c7e..ad11856f 100644 --- a/test/docker/Dockerfile +++ b/test/docker/Dockerfile @@ -1,4 +1,4 @@ -ARG GO_IMAGE=golang:1.20.5 +ARG GO_IMAGE=golang:1.20.14 FROM $GO_IMAGE # Copy SDK code into the container From 7914b596ba9b038ef5ccc9a2f7ce7fcb6f45b0b2 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 24 Apr 2024 11:18:47 -0400 Subject: [PATCH 3/8] Incentives: Add fields in block header for proposer and fees collected. (#617) * Add fields in block header for proposer and fees collected. * Add payouts related fields to Account * update consensus.go * Add absent participation accounts --- protocol/config/consensus.go | 122 +++++++++++++++++++++++++++++++++-- types/block.go | 23 +++++++ types/statedelta.go | 4 ++ 3 files changed, 145 insertions(+), 4 deletions(-) diff --git a/protocol/config/consensus.go b/protocol/config/consensus.go index 94ce41be..6719f10f 100644 --- a/protocol/config/consensus.go +++ b/protocol/config/consensus.go @@ -428,8 +428,8 @@ type ConsensusParams struct { EnableExtraPagesOnAppUpdate bool - // MaxProposedExpiredOnlineAccounts is the maximum number of online accounts, which need - // to be taken offline, that would be proposed to be taken offline. + // MaxProposedExpiredOnlineAccounts is the maximum number of online accounts + // that a proposer can take offline for having expired voting keys. MaxProposedExpiredOnlineAccounts int // EnableAccountDataResourceSeparation enables the support for extended application and asset storage @@ -510,6 +510,101 @@ type ConsensusParams struct { // arrival times or is set to a static value. Even if this flag disables the // dynamic filter, it will be calculated and logged (but not used). DynamicFilterTimeout bool + + // Payouts contains parameters for amounts and eligibility for block proposer + // payouts. It excludes information about the "unsustainable" payouts + // described in BonusPlan. + Payouts ProposerPayoutRules + + // Bonus contains parameters related to the extra payout made to block + // proposers, unrelated to the fees paid in that block. For it to actually + // occur, extra funds need to be put into the FeeSink. The bonus amount + // decays exponentially. + Bonus BonusPlan +} + +// ProposerPayoutRules puts several related consensus parameters in one place. The same +// care for backward compatibility with old blocks must be taken. +type ProposerPayoutRules struct { + // Enabled turns on several things needed for paying block incentives, + // including tracking of the proposer and fees collected. + Enabled bool + + // GoOnlineFee imparts a small cost on moving from offline to online. This + // will impose a cost to running unreliable nodes that get suspended and + // then come back online. + GoOnlineFee uint64 + + // Percent specifies the percent of fees paid in a block that go to the + // proposer instead of the FeeSink. + Percent uint64 + + // MinBalance is the minimum balance an account must have to be eligible for + // incentives. It ensures that smaller accounts continue to operate for the + // same motivations they had before block incentives were + // introduced. Without that assurance, it is difficult to model their + // behaviour - might many participants join for the hope of easy financial + // rewards, but without caring enough to run a high-quality node? + MinBalance uint64 + + // MaxBalance is the maximum balance an account can have to be eligible for + // incentives. It encourages large accounts to split their stake to add + // resilience to consensus in the case of outages. Nothing in protocol can + // prevent such accounts from running nodes that share fate (same machine, + // same data center, etc), but this serves as a gentle reminder. + MaxBalance uint64 + + // MaxMarkAbsent is the maximum number of online accounts, that a proposer + // can suspend for not proposing "lately" (In 10x expected interval, or + // within a grace period from being challenged) + MaxMarkAbsent int + + // Challenges occur once every challengeInterval rounds. + ChallengeInterval uint64 + // Suspensions happen between 1 and 2 grace periods after a challenge. Must + // be less than half MaxTxnLife to ensure the Block header will be cached + // and less than half ChallengeInterval to avoid overlapping challenges. A larger + // grace period means larger stake nodes will probably propose before they + // need to consider an active heartbeat. + ChallengeGracePeriod uint64 + // An account is challenged if the first challengeBits match the start of + // the account address. An online account will be challenged about once + // every interval*2^bits rounds. + ChallengeBits int +} + +// BonusPlan describes how the "extra" proposer payouts are to be made. It +// specifies an exponential decay in which the bonus decreases by 1% every n +// rounds. If we need to change the decay rate (only), we would create a new +// plan like: +// +// BaseAmount: 0, DecayInterval: XXX +// +// by using a zero baseAmount, the amount not affected. +// For a bigger change, we'd use a plan like: +// +// BaseRound: , BaseAmount: , DecayInterval: +// +// or just +// +// BaseAmount: , DecayInterval: +// +// the new decay rate would go into effect at upgrade time, and the new +// amount would be set at baseRound or at upgrade time. +type BonusPlan struct { + // BaseRound is the earliest round this plan can apply. Of course, the + // consensus update must also have happened. So using a low value makes it + // go into effect immediately upon upgrade. + BaseRound uint64 + // BaseAmount is the bonus to be paid when this plan first applies (see + // baseRound). If it is zero, then no explicit change is made to the bonus + // (useful for only changing the decay rate). + BaseAmount uint64 + // DecayInterval is the time in rounds between 1% decays. For simplicity, + // decay occurs based on round % BonusDecayInterval, so a decay can happen right + // after going into effect. The BonusDecayInterval goes into effect at upgrade + // time, regardless of `baseRound`. + DecayInterval uint64 } // PaysetCommitType enumerates possible ways for the block header to commit to @@ -584,10 +679,14 @@ var MaxExtraAppProgramLen int // supported supported by any of the consensus protocols. used for decoding purposes. var MaxAvailableAppProgramLen int -// MaxProposedExpiredOnlineAccounts is the maximum number of online accounts, which need -// to be taken offline, that would be proposed to be taken offline. +// MaxProposedExpiredOnlineAccounts is the maximum number of online accounts +// that a proposer can take offline for having expired voting keys. var MaxProposedExpiredOnlineAccounts int +// MaxMarkAbsent is the maximum number of online accounts that a proposer can +// suspend for not proposing "lately" +var MaxMarkAbsent int + // MaxAppTotalArgLen is the maximum number of bytes across all arguments of an application // max sum([len(arg) for arg in txn.ApplicationArgs]) var MaxAppTotalArgLen int @@ -661,6 +760,7 @@ func checkSetAllocBounds(p ConsensusParams) { checkSetMax(p.MaxAppProgramLen, &MaxLogCalls) checkSetMax(p.MaxInnerTransactions*p.MaxTxGroupSize, &MaxInnerTransactionsPerDelta) checkSetMax(p.MaxProposedExpiredOnlineAccounts, &MaxProposedExpiredOnlineAccounts) + checkSetMax(p.Payouts.MaxMarkAbsent, &MaxMarkAbsent) // These bounds are exported to make them available to the msgp generator for calculating // maximum valid message size for each message going across the wire. @@ -1323,6 +1423,20 @@ func initConsensusProtocols() { vFuture.LogicSigVersion = 11 // When moving this to a release, put a new higher LogicSigVersion here + vFuture.Payouts.Enabled = true + vFuture.Payouts.Percent = 75 + vFuture.Payouts.GoOnlineFee = 2_000_000 // 2 algos + vFuture.Payouts.MinBalance = 30_000_000_000 // 30,000 algos + vFuture.Payouts.MaxBalance = 70_000_000_000_000 // 70M algos + vFuture.Payouts.MaxMarkAbsent = 32 + vFuture.Payouts.ChallengeInterval = 1000 + vFuture.Payouts.ChallengeGracePeriod = 200 + vFuture.Payouts.ChallengeBits = 5 + + vFuture.Bonus.BaseAmount = 10_000_000 // 10 Algos + // 2.9 sec rounds gives about 10.8M rounds per year. + vFuture.Bonus.DecayInterval = 250_000 // .99^(10.8/0.25) ~ .648. So 35% decay per year + Consensus[protocol.ConsensusFuture] = vFuture // vAlphaX versions are an separate series of consensus parameters and versions for alphanet diff --git a/types/block.go b/types/block.go index 213fa86c..dcddb468 100644 --- a/types/block.go +++ b/types/block.go @@ -28,6 +28,25 @@ type ( // Genesis hash to which this block belongs. GenesisHash Digest `codec:"gh"` + // Proposer is the proposer of this block. Like the Seed, agreement adds + // this after the block is assembled by the transaction pool, so that the same block can be prepared + // for multiple participating accounts in the same node. Populated if proto.Payouts.Enabled + Proposer Address `codec:"prp"` + + // FeesCollected is the sum of all fees paid by transactions in this + // block. Populated if proto.EnableMining. + FeesCollected MicroAlgos `codec:"fc"` + + // Bonus is the bonus incentive to be paid for proposing this block. It + // begins as a consensus parameter value, and decays periodically. + Bonus MicroAlgos `codec:"bi"` + + // ProposerPayout is the amount that should be moved from the FeeSink to + // the Proposer at the start of the next block. It is basically the + // bonus + the payouts percent of FeesCollected, but may be zero'd by + // proposer ineligibility. + ProposerPayout MicroAlgos `codec:"pp"` + // Rewards. // // When a block is applied, some amount of rewards are accrued to @@ -115,6 +134,10 @@ type ( // that needs to be converted to offline since their // participation key expired. ExpiredParticipationAccounts []Address `codec:"partupdrmv"` + + // AbsentParticipationAccounts contains a list of online accounts that + // needs to be converted to offline since they are not proposing. + AbsentParticipationAccounts []Address `codec:"partupdabs"` } // RewardsState represents the global parameters controlling the rate diff --git a/types/statedelta.go b/types/statedelta.go index 84c3a00c..405b8d92 100644 --- a/types/statedelta.go +++ b/types/statedelta.go @@ -159,6 +159,7 @@ type AccountBaseData struct { RewardsBase uint64 RewardedMicroAlgos MicroAlgos AuthAddr Address + IncentiveEligible bool TotalAppSchema StateSchema // Totals across created globals, and opted in locals. TotalExtraAppPages uint32 // Total number of extra pages across all created apps @@ -168,6 +169,9 @@ type AccountBaseData struct { TotalAssets uint64 // Total of asset creations and optins (i.e. number of holdings) TotalBoxes uint64 // Total number of boxes associated to this account TotalBoxBytes uint64 // Total bytes for this account's boxes. keys _and_ values count + + LastProposed Round // The last round that this account proposed the winning block. + LastHeartbeat Round // The last round that this account sent a heartbeat to show it was online. } // AccountData provides users of the Balances interface per-account data (like basics.AccountData) From 801e5598bb89b9c5a5adc717642bf77341ac1456 Mon Sep 17 00:00:00 2001 From: tianzedavid <168427849+tianzedavid@users.noreply.github.com> Date: Wed, 1 May 2024 22:39:13 +0800 Subject: [PATCH 4/8] chore: fix function names (#632) Signed-off-by: tianzedavid --- client/v2/algod/algod.go | 2 +- client/v2/indexer/indexer.go | 2 +- transaction/transaction.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/v2/algod/algod.go b/client/v2/algod/algod.go index 48deecf4..3e27a010 100644 --- a/client/v2/algod/algod.go +++ b/client/v2/algod/algod.go @@ -27,7 +27,7 @@ func (c *Client) getMsgpack(ctx context.Context, response interface{}, path stri return (*common.Client)(c).GetRawMsgpack(ctx, response, path, body, headers) } -// getMsgpack performs a GET request to the specific path against the server, assumes msgpack response +// getRaw performs a GET request to the specific path against the server, assumes msgpack response func (c *Client) getRaw(ctx context.Context, path string, body interface{}, headers []*common.Header) ([]byte, error) { return (*common.Client)(c).GetRaw(ctx, path, body, headers) } diff --git a/client/v2/indexer/indexer.go b/client/v2/indexer/indexer.go index e0e5cf2c..d35e503b 100644 --- a/client/v2/indexer/indexer.go +++ b/client/v2/indexer/indexer.go @@ -26,7 +26,7 @@ func (c *Client) getMsgpack(ctx context.Context, response interface{}, path stri return (*common.Client)(c).GetRawMsgpack(ctx, response, path, body, headers) } -// getMsgpack performs a GET request to the specific path against the server, assumes msgpack response +// getRaw performs a GET request to the specific path against the server, assumes msgpack response func (c *Client) getRaw(ctx context.Context, path string, body interface{}, headers []*common.Header) ([]byte, error) { return (*common.Client)(c).GetRaw(ctx, path, body, headers) } diff --git a/transaction/transaction.go b/transaction/transaction.go index b7d40715..46c06c65 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -556,7 +556,7 @@ func byte32FromBase64(in string) (out [32]byte, err error) { return } -// byte32FromBase64 decodes the input base64 string and outputs a +// byte64FromBase64 decodes the input base64 string and outputs a // 64 byte array, erroring if the input is the wrong length. func byte64FromBase64(in string) (out [64]byte, err error) { slice, err := base64.StdEncoding.DecodeString(in) From 3a7c4ec67c2342a13453b550e8a3d0bcafb5c8ae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 10:50:40 -0400 Subject: [PATCH 5/8] Regenerate code from specification file (#631) Co-authored-by: Algorand Generation Bot --- client/v2/algod/algod.go | 4 ++ client/v2/algod/getBlockLogs.go | 23 +++++++++ client/v2/common/models/account.go | 48 +++++++++++-------- .../v2/common/models/account_participation.go | 16 +++---- client/v2/common/models/app_call_logs.go | 14 ++++++ client/v2/common/models/application.go | 4 +- .../common/models/application_local_state.go | 4 +- .../v2/common/models/application_log_data.go | 2 +- client/v2/common/models/application_params.go | 12 ++--- .../common/models/application_state_schema.go | 4 +- client/v2/common/models/asset_holding.go | 4 +- client/v2/common/models/asset_params.go | 39 ++++++++------- client/v2/common/models/block.go | 12 +++++ .../v2/common/models/block_logs_response.go | 13 +++++ .../v2/common/models/participation_updates.go | 4 ++ client/v2/common/models/teal_value.go | 6 +-- 16 files changed, 144 insertions(+), 65 deletions(-) create mode 100644 client/v2/algod/getBlockLogs.go create mode 100644 client/v2/common/models/app_call_logs.go create mode 100644 client/v2/common/models/block_logs_response.go diff --git a/client/v2/algod/algod.go b/client/v2/algod/algod.go index 3e27a010..1c631e7a 100644 --- a/client/v2/algod/algod.go +++ b/client/v2/algod/algod.go @@ -110,6 +110,10 @@ func (c *Client) GetTransactionProof(round uint64, txid string) *GetTransactionP return &GetTransactionProof{c: c, round: round, txid: txid} } +func (c *Client) GetBlockLogs(round uint64) *GetBlockLogs { + return &GetBlockLogs{c: c, round: round} +} + func (c *Client) Supply() *Supply { return &Supply{c: c} } diff --git a/client/v2/algod/getBlockLogs.go b/client/v2/algod/getBlockLogs.go new file mode 100644 index 00000000..c0f9354d --- /dev/null +++ b/client/v2/algod/getBlockLogs.go @@ -0,0 +1,23 @@ +package algod + +import ( + "context" + "fmt" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/common" + "github.com/algorand/go-algorand-sdk/v2/client/v2/common/models" +) + +// GetBlockLogs get all of the logs from outer and inner app calls in the given +// round +type GetBlockLogs struct { + c *Client + + round uint64 +} + +// Do performs the HTTP request +func (s *GetBlockLogs) Do(ctx context.Context, headers ...*common.Header) (response models.BlockLogsResponse, err error) { + err = s.c.get(ctx, &response, fmt.Sprintf("/v2/blocks/%s/logs", common.EscapeParams(s.round)...), nil, headers) + return +} diff --git a/client/v2/common/models/account.go b/client/v2/common/models/account.go index c394ca61..6556868f 100644 --- a/client/v2/common/models/account.go +++ b/client/v2/common/models/account.go @@ -7,44 +7,44 @@ type Account struct { // Address the account public key Address string `json:"address"` - // Amount (algo) total number of MicroAlgos in the account + // Amount total number of MicroAlgos in the account Amount uint64 `json:"amount"` // AmountWithoutPendingRewards specifies the amount of MicroAlgos in the account, // without the pending rewards. AmountWithoutPendingRewards uint64 `json:"amount-without-pending-rewards"` - // AppsLocalState (appl) applications local data stored in this account. + // AppsLocalState application local data stored in this account. // Note the raw object uses `map[int] -> AppLocalState` for this type. AppsLocalState []ApplicationLocalState `json:"apps-local-state,omitempty"` - // AppsTotalExtraPages (teap) the sum of all extra application program pages for - // this account. + // AppsTotalExtraPages the sum of all extra application program pages for this + // account. AppsTotalExtraPages uint64 `json:"apps-total-extra-pages,omitempty"` - // AppsTotalSchema (tsch) stores the sum of all of the local schemas and global - // schemas in this account. + // AppsTotalSchema the sum of all of the local schemas and global schemas in this + // account. // Note: the raw account uses `StateSchema` for this type. AppsTotalSchema ApplicationStateSchema `json:"apps-total-schema,omitempty"` - // Assets (asset) assets held by this account. + // Assets assets held by this account. // Note the raw object uses `map[int] -> AssetHolding` for this type. Assets []AssetHolding `json:"assets,omitempty"` - // AuthAddr (spend) the address against which signing should be checked. If empty, - // the address of the current account is used. This field can be updated in any + // AuthAddr the address against which signing should be checked. If empty, the + // address of the current account is used. This field can be updated in any // transaction by setting the RekeyTo field. AuthAddr string `json:"auth-addr,omitempty"` // ClosedAtRound round during which this account was most recently closed. ClosedAtRound uint64 `json:"closed-at-round,omitempty"` - // CreatedApps (appp) parameters of applications created by this account including - // app global data. + // CreatedApps parameters of applications created by this account including app + // global data. // Note: the raw account uses `map[int] -> AppParams` for this type. CreatedApps []Application `json:"created-apps,omitempty"` - // CreatedAssets (apar) parameters of assets created by this account. + // CreatedAssets parameters of assets created by this account. // Note: the raw account uses `map[int] -> Asset` for this type. CreatedAssets []Asset `json:"created-assets,omitempty"` @@ -54,6 +54,17 @@ type Account struct { // Deleted whether or not this account is currently closed. Deleted bool `json:"deleted,omitempty"` + // IncentiveEligible can the account receive block incentives if its balance is in + // range at proposal time. + IncentiveEligible bool `json:"incentive-eligible,omitempty"` + + // LastHeartbeat the round in which this account last went online, or explicitly + // renewed their online status. + LastHeartbeat uint64 `json:"last-heartbeat,omitempty"` + + // LastProposed the round in which this account last proposed the block. + LastProposed uint64 `json:"last-proposed,omitempty"` + // Participation accountParticipation describes the parameters used by this account // in consensus protocol. Participation AccountParticipation `json:"participation,omitempty"` @@ -61,26 +72,25 @@ type Account struct { // PendingRewards amount of MicroAlgos of pending rewards in this account. PendingRewards uint64 `json:"pending-rewards"` - // RewardBase (ebase) used as part of the rewards computation. Only applicable to - // accounts which are participating. + // RewardBase used as part of the rewards computation. Only applicable to accounts + // which are participating. RewardBase uint64 `json:"reward-base,omitempty"` - // Rewards (ern) total rewards of MicroAlgos the account has received, including - // pending rewards. + // Rewards total rewards of MicroAlgos the account has received, including pending + // rewards. Rewards uint64 `json:"rewards"` // Round the round for which this information is relevant. Round uint64 `json:"round"` - // SigType indicates what type of signature is used by this account, must be one - // of: + // SigType the type of signature used by this account, must be one of: // * sig // * msig // * lsig // * or null if unknown SigType string `json:"sig-type,omitempty"` - // Status (onl) delegation status of the account's MicroAlgos + // Status voting status of the account's MicroAlgos // * Offline - indicates that the associated account is delegated. // * Online - indicates that the associated account used as part of the delegation // pool. diff --git a/client/v2/common/models/account_participation.go b/client/v2/common/models/account_participation.go index f7f51b82..a94dbd7b 100644 --- a/client/v2/common/models/account_participation.go +++ b/client/v2/common/models/account_participation.go @@ -3,23 +3,23 @@ package models // AccountParticipation accountParticipation describes the parameters used by this // account in consensus protocol. type AccountParticipation struct { - // SelectionParticipationKey (sel) Selection public key (if any) currently - // registered for this round. + // SelectionParticipationKey selection public key (if any) currently registered for + // this round. SelectionParticipationKey []byte `json:"selection-participation-key"` - // StateProofKey (stprf) Root of the state proof key (if any) + // StateProofKey root of the state proof key (if any) StateProofKey []byte `json:"state-proof-key,omitempty"` - // VoteFirstValid (voteFst) First round for which this participation is valid. + // VoteFirstValid first round for which this participation is valid. VoteFirstValid uint64 `json:"vote-first-valid"` - // VoteKeyDilution (voteKD) Number of subkeys in each batch of participation keys. + // VoteKeyDilution number of subkeys in each batch of participation keys. VoteKeyDilution uint64 `json:"vote-key-dilution"` - // VoteLastValid (voteLst) Last round for which this participation is valid. + // VoteLastValid last round for which this participation is valid. VoteLastValid uint64 `json:"vote-last-valid"` - // VoteParticipationKey (vote) root participation public key (if any) currently - // registered for this round. + // VoteParticipationKey root participation public key (if any) currently registered + // for this round. VoteParticipationKey []byte `json:"vote-participation-key"` } diff --git a/client/v2/common/models/app_call_logs.go b/client/v2/common/models/app_call_logs.go new file mode 100644 index 00000000..dd48f389 --- /dev/null +++ b/client/v2/common/models/app_call_logs.go @@ -0,0 +1,14 @@ +package models + +// AppCallLogs the logged messages from an app call along with the app ID and outer +// transaction ID. Logs appear in the same order that they were emitted. +type AppCallLogs struct { + // ApplicationIndex the application from which the logs were generated + ApplicationIndex uint64 `json:"application-index"` + + // Logs an array of logs + Logs [][]byte `json:"logs"` + + // Txid the transaction ID of the outer app call that lead to these logs + Txid string `json:"txId"` +} diff --git a/client/v2/common/models/application.go b/client/v2/common/models/application.go index 0d7acdf1..9cc8db00 100644 --- a/client/v2/common/models/application.go +++ b/client/v2/common/models/application.go @@ -11,9 +11,9 @@ type Application struct { // DeletedAtRound round when this application was deleted. DeletedAtRound uint64 `json:"deleted-at-round,omitempty"` - // Id (appidx) application index. + // Id application index. Id uint64 `json:"id"` - // Params (appparams) application parameters. + // Params application parameters. Params ApplicationParams `json:"params"` } diff --git a/client/v2/common/models/application_local_state.go b/client/v2/common/models/application_local_state.go index 397a8fdd..3d5d71d0 100644 --- a/client/v2/common/models/application_local_state.go +++ b/client/v2/common/models/application_local_state.go @@ -12,12 +12,12 @@ type ApplicationLocalState struct { // Id the application which this local state is for. Id uint64 `json:"id"` - // KeyValue (tkv) storage. + // KeyValue storage. KeyValue []TealKeyValue `json:"key-value,omitempty"` // OptedInAtRound round when the account opted into the application. OptedInAtRound uint64 `json:"opted-in-at-round,omitempty"` - // Schema (hsch) schema. + // Schema schema. Schema ApplicationStateSchema `json:"schema"` } diff --git a/client/v2/common/models/application_log_data.go b/client/v2/common/models/application_log_data.go index 0bf569a2..28e39621 100644 --- a/client/v2/common/models/application_log_data.go +++ b/client/v2/common/models/application_log_data.go @@ -2,7 +2,7 @@ package models // ApplicationLogData stores the global information associated with an application. type ApplicationLogData struct { - // Logs (lg) Logs for the application being executed by the transaction. + // Logs logs for the application being executed by the transaction. Logs [][]byte `json:"logs"` // Txid transaction ID diff --git a/client/v2/common/models/application_params.go b/client/v2/common/models/application_params.go index 4eed80aa..f40c3c75 100644 --- a/client/v2/common/models/application_params.go +++ b/client/v2/common/models/application_params.go @@ -2,25 +2,25 @@ package models // ApplicationParams stores the global information associated with an application. type ApplicationParams struct { - // ApprovalProgram (approv) approval program. + // ApprovalProgram approval program. ApprovalProgram []byte `json:"approval-program"` - // ClearStateProgram (clearp) approval program. + // ClearStateProgram clear state program. ClearStateProgram []byte `json:"clear-state-program"` // Creator the address that created this application. This is the address where the // parameters and global state for this application can be found. Creator string `json:"creator,omitempty"` - // ExtraProgramPages (epp) the amount of extra program pages available to this app. + // ExtraProgramPages the number of extra program pages available to this app. ExtraProgramPages uint64 `json:"extra-program-pages,omitempty"` - // GlobalState [\gs) global schema + // GlobalState global state GlobalState []TealKeyValue `json:"global-state,omitempty"` - // GlobalStateSchema [\gsch) global schema + // GlobalStateSchema global schema GlobalStateSchema ApplicationStateSchema `json:"global-state-schema,omitempty"` - // LocalStateSchema [\lsch) local schema + // LocalStateSchema local schema LocalStateSchema ApplicationStateSchema `json:"local-state-schema,omitempty"` } diff --git a/client/v2/common/models/application_state_schema.go b/client/v2/common/models/application_state_schema.go index 4040aacf..f6b7b36e 100644 --- a/client/v2/common/models/application_state_schema.go +++ b/client/v2/common/models/application_state_schema.go @@ -3,9 +3,9 @@ package models // ApplicationStateSchema specifies maximums on the number of each type that may be // stored. type ApplicationStateSchema struct { - // NumByteSlice (nbs) num of byte slices. + // NumByteSlice number of byte slices. NumByteSlice uint64 `json:"num-byte-slice"` - // NumUint (nui) num of uints. + // NumUint number of uints. NumUint uint64 `json:"num-uint"` } diff --git a/client/v2/common/models/asset_holding.go b/client/v2/common/models/asset_holding.go index 033750a2..34f1a102 100644 --- a/client/v2/common/models/asset_holding.go +++ b/client/v2/common/models/asset_holding.go @@ -4,7 +4,7 @@ package models // Definition: // data/basics/userBalance.go : AssetHolding type AssetHolding struct { - // Amount (a) number of units held. + // Amount number of units held. Amount uint64 `json:"amount"` // AssetId asset ID of the holding. @@ -13,7 +13,7 @@ type AssetHolding struct { // Deleted whether or not the asset holding is currently deleted from its account. Deleted bool `json:"deleted,omitempty"` - // IsFrozen (f) whether or not the holding is frozen. + // IsFrozen whether or not the holding is frozen. IsFrozen bool `json:"is-frozen"` // OptedInAtRound round during which the account opted into this asset holding. diff --git a/client/v2/common/models/asset_params.go b/client/v2/common/models/asset_params.go index 6dbf7a0a..7fdba068 100644 --- a/client/v2/common/models/asset_params.go +++ b/client/v2/common/models/asset_params.go @@ -5,8 +5,8 @@ package models // Definition: // data/transactions/asset.go : AssetParams type AssetParams struct { - // Clawback (c) Address of account used to clawback holdings of this asset. If - // empty, clawback is not permitted. + // Clawback address of account used to clawback holdings of this asset. If empty, + // clawback is not permitted. Clawback string `json:"clawback,omitempty"` // Creator the address that created this asset. This is the address where the @@ -14,51 +14,50 @@ type AssetParams struct { // asset units can be sent in the worst case. Creator string `json:"creator"` - // Decimals (dc) The number of digits to use after the decimal point when - // displaying this asset. If 0, the asset is not divisible. If 1, the base unit of - // the asset is in tenths. If 2, the base unit of the asset is in hundredths, and - // so on. This value must be between 0 and 19 (inclusive). + // Decimals the number of digits to use after the decimal point when displaying + // this asset. If 0, the asset is not divisible. If 1, the base unit of the asset + // is in tenths. If 2, the base unit of the asset is in hundredths, and so on. This + // value must be between 0 and 19 (inclusive). Decimals uint64 `json:"decimals"` - // DefaultFrozen (df) Whether holdings of this asset are frozen by default. + // DefaultFrozen whether holdings of this asset are frozen by default. DefaultFrozen bool `json:"default-frozen,omitempty"` - // Freeze (f) Address of account used to freeze holdings of this asset. If empty, + // Freeze address of account used to freeze holdings of this asset. If empty, // freezing is not permitted. Freeze string `json:"freeze,omitempty"` - // Manager (m) Address of account used to manage the keys of this asset and to - // destroy it. + // Manager address of account used to manage the keys of this asset and to destroy + // it. Manager string `json:"manager,omitempty"` - // MetadataHash (am) A commitment to some unspecified asset metadata. The format of - // this metadata is up to the application. + // MetadataHash a commitment to some unspecified asset metadata. The format of this + // metadata is up to the application. MetadataHash []byte `json:"metadata-hash,omitempty"` - // Name (an) Name of this asset, as supplied by the creator. Included only when the + // Name name of this asset, as supplied by the creator. Included only when the // asset name is composed of printable utf-8 characters. Name string `json:"name,omitempty"` // NameB64 base64 encoded name of this asset, as supplied by the creator. NameB64 []byte `json:"name-b64,omitempty"` - // Reserve (r) Address of account holding reserve (non-minted) units of this asset. + // Reserve address of account holding reserve (non-minted) units of this asset. Reserve string `json:"reserve,omitempty"` - // Total (t) The total number of units of this asset. + // Total the total number of units of this asset. Total uint64 `json:"total"` - // UnitName (un) Name of a unit of this asset, as supplied by the creator. Included - // only when the name of a unit of this asset is composed of printable utf-8 - // characters. + // UnitName name of a unit of this asset, as supplied by the creator. Included only + // when the name of a unit of this asset is composed of printable utf-8 characters. UnitName string `json:"unit-name,omitempty"` // UnitNameB64 base64 encoded name of a unit of this asset, as supplied by the // creator. UnitNameB64 []byte `json:"unit-name-b64,omitempty"` - // Url (au) URL where more information about the asset can be retrieved. Included - // only when the URL is composed of printable utf-8 characters. + // Url uRL where more information about the asset can be retrieved. Included only + // when the URL is composed of printable utf-8 characters. Url string `json:"url,omitempty"` // UrlB64 base64 encoded URL where more information about the asset can be diff --git a/client/v2/common/models/block.go b/client/v2/common/models/block.go index 425c40f7..abd3621b 100644 --- a/client/v2/common/models/block.go +++ b/client/v2/common/models/block.go @@ -4,6 +4,12 @@ package models // Definition: // data/bookkeeping/block.go : Block type Block struct { + // Bonus the potential bonus payout for this block. + Bonus uint64 `json:"bonus,omitempty"` + + // FeesCollected the sum of all fees paid by transactions in this block. + FeesCollected uint64 `json:"fees-collected,omitempty"` + // GenesisHash (gh) hash to which this block belongs. GenesisHash []byte `json:"genesis-hash"` @@ -17,6 +23,12 @@ type Block struct { // PreviousBlockHash (prev) Previous block hash. PreviousBlockHash []byte `json:"previous-block-hash"` + // Proposer the proposer of this block. + Proposer string `json:"proposer,omitempty"` + + // ProposerPayout the actual amount transferred to the proposer from the fee sink. + ProposerPayout uint64 `json:"proposer-payout,omitempty"` + // Rewards fields relating to rewards, Rewards BlockRewards `json:"rewards,omitempty"` diff --git a/client/v2/common/models/block_logs_response.go b/client/v2/common/models/block_logs_response.go new file mode 100644 index 00000000..d5d1e140 --- /dev/null +++ b/client/v2/common/models/block_logs_response.go @@ -0,0 +1,13 @@ +package models + +// BlockLogsResponse all logs emitted in the given round. Each app call, whether +// top-level or inner, that contains logs results in a separate AppCallLogs object. +// Therefore there may be multiple AppCallLogs with the same application ID and +// outer transaction ID in the event of multiple inner app calls to the same app. +// App calls with no logs are not included in the response. AppCallLogs are +// returned in the same order that their corresponding app call appeared in the +// block (pre-order traversal of inner app calls) +type BlockLogsResponse struct { + // Logs + Logs []AppCallLogs `json:"logs"` +} diff --git a/client/v2/common/models/participation_updates.go b/client/v2/common/models/participation_updates.go index 74c97fab..06dfe762 100644 --- a/client/v2/common/models/participation_updates.go +++ b/client/v2/common/models/participation_updates.go @@ -3,6 +3,10 @@ package models // ParticipationUpdates participation account data that needs to be checked/acted // on by the network. type ParticipationUpdates struct { + // AbsentParticipationAccounts (partupabs) a list of online accounts that need to + // be suspended. + AbsentParticipationAccounts []string `json:"absent-participation-accounts,omitempty"` + // ExpiredParticipationAccounts (partupdrmv) a list of online accounts that needs // to be converted to offline since their participation key expired. ExpiredParticipationAccounts []string `json:"expired-participation-accounts,omitempty"` diff --git a/client/v2/common/models/teal_value.go b/client/v2/common/models/teal_value.go index 40003898..21594c4a 100644 --- a/client/v2/common/models/teal_value.go +++ b/client/v2/common/models/teal_value.go @@ -2,13 +2,13 @@ package models // TealValue represents a TEAL value. type TealValue struct { - // Bytes (tb) bytes value. + // Bytes bytes value. Bytes string `json:"bytes"` - // Type (tt) value type. Value `1` refers to **bytes**, value `2` refers to + // Type type of the value. Value `1` refers to **bytes**, value `2` refers to // **uint** Type uint64 `json:"type"` - // Uint (ui) uint value. + // Uint uint value. Uint uint64 `json:"uint"` } From dde38d8d139e1587b401a3301f1c2fe74dd55c8b Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Wed, 8 May 2024 14:34:08 -0400 Subject: [PATCH 6/8] Fix funding for cucumber tests by rotating sender accounts (#630) --- test/applications_integration_test.go | 16 ++++++++++++--- test/steps_test.go | 28 ++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/test/applications_integration_test.go b/test/applications_integration_test.go index 02466f86..9003f4a4 100644 --- a/test/applications_integration_test.go +++ b/test/applications_integration_test.go @@ -60,11 +60,17 @@ func iCreateANewTransientAccountAndFundItWithMicroalgos(microalgos int) error { } params.Fee = types.MicroAlgos(fee) - ltxn, err := transaction.MakePaymentTxn(accounts[1], transientAccount.Address.String(), uint64(microalgos), note, close, params) + + funder, err := fundingAccount(algodV2client, uint64(microalgos)) + if err != nil { + return err + } + + ltxn, err := transaction.MakePaymentTxn(funder, transientAccount.Address.String(), uint64(microalgos), note, close, params) if err != nil { return err } - lsk, err := kcl.ExportKey(handle, walletPswd, accounts[1]) + lsk, err := kcl.ExportKey(handle, walletPswd, funder) if err != nil { return err } @@ -91,7 +97,11 @@ func iFundTheCurrentApplicationsAddress(microalgos int) error { return err } - txn, err := transaction.MakePaymentTxn(accounts[0], address.String(), uint64(microalgos), nil, "", params) + funder, err := fundingAccount(algodV2client, uint64(microalgos)) + if err != nil { + return err + } + txn, err := transaction.MakePaymentTxn(funder, address.String(), uint64(microalgos), nil, "", params) if err != nil { return err } diff --git a/test/steps_test.go b/test/steps_test.go index 85779912..bd5dbd80 100644 --- a/test/steps_test.go +++ b/test/steps_test.go @@ -10,6 +10,7 @@ import ( "encoding/json" "flag" "fmt" + "math/rand" "os" "path" "reflect" @@ -148,13 +149,38 @@ func waitForAlgodInDevMode() { time.Sleep(500 * time.Millisecond) } +// fundingAccount finds an account with enough funds to fund the given amount +func fundingAccount(client *algodV2.Client, amount uint64) (string, error) { + // Random shuffle to spread the load + shuffledAccounts := make([]string, len(accounts)) + copy(shuffledAccounts, accounts) + rand.Shuffle(len(shuffledAccounts), func(i, j int) { + shuffledAccounts[i], shuffledAccounts[j] = shuffledAccounts[j], shuffledAccounts[i] + }) + for _, accountAddress := range shuffledAccounts { + res, err := client.AccountInformation(accountAddress).Do(context.Background()) + if err != nil { + return "", err + } + if res.Amount < amount+100_000 { // 100,000 microalgos is default account min balance + continue + } + return accountAddress, nil + } + return "", fmt.Errorf("no account has enough to fund %d microalgos", amount) +} + func initializeAccount(accountAddress string) error { params, err := aclv2.SuggestedParams().Do(context.Background()) if err != nil { return err } - txn, err = transaction.MakePaymentTxn(accounts[0], accountAddress, devModeInitialAmount, []byte{}, "", params) + funder, err := fundingAccount(aclv2, devModeInitialAmount) + if err != nil { + return err + } + txn, err = transaction.MakePaymentTxn(funder, accountAddress, devModeInitialAmount, []byte{}, "", params) if err != nil { return err } From 5814c9940ddcb0bc4cbf88579b4e014f587fe2fc Mon Sep 17 00:00:00 2001 From: Gary <982483+gmalouf@users.noreply.github.com> Date: Wed, 8 May 2024 15:19:12 -0400 Subject: [PATCH 7/8] Build: Bump golang version to 1.21.10 (#636) * Bump golang version to 1.21.10 * Address new linter warnings. --- .circleci/config.yml | 4 ++-- .github/workflows/reviewdog.yml | 8 ++++---- go.mod | 4 +++- go.sum | 1 + test/docker/Dockerfile | 2 +- test/helpers.go | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 85d2e3cf..ebdc0f6d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 orbs: - go: circleci/go@1.7.3 + go: circleci/go@1.11.0 workflows: circleci_build_and_test: @@ -10,7 +10,7 @@ workflows: name: 'test_go_<< matrix.go_version >>' matrix: parameters: - go_version: ['1.20.14'] + go_version: ['1.21.10'] jobs: test: diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 4cb4b7b5..a595b8bf 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -12,17 +12,17 @@ jobs: - name: Install specific golang uses: actions/setup-go@v4.0.1 with: - go-version: '1.20.14' + go-version: '1.21.10' - name: Check format run: test -z `go fmt ./...` - name: Vet run: go vet ./... - name: reviewdog-golangci-lint - uses: reviewdog/action-golangci-lint@v2.3.1 + uses: reviewdog/action-golangci-lint@v2.6.1 with: - golangci_lint_version: "v1.53.2" + golangci_lint_version: "v1.58.0" golangci_lint_flags: "-c .golangci.yml --allow-parallel-runners" - go_version: "1.20.14" + go_version: "1.21.10" reporter: "github-pr-review" tool_name: "Lint Errors" level: "error" diff --git a/go.mod b/go.mod index 37b32c8f..7040cd37 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/algorand/go-algorand-sdk/v2 -go 1.20 +go 1.21 + +toolchain go1.21.10 require ( github.com/algorand/avm-abi v0.1.1 diff --git a/go.sum b/go.sum index 960ca0a0..e8b1fb2b 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ github.com/algorand/avm-abi v0.1.1/go.mod h1:+CgwM46dithy850bpTeHh9MC99zpn2Snirb github.com/algorand/go-codec/codec v1.1.10 h1:zmWYU1cp64jQVTOG8Tw8wa+k0VfwgXIPbnDfiVa+5QA= github.com/algorand/go-codec/codec v1.1.10/go.mod h1:YkEx5nmr/zuCeaDYOIhlDg92Lxju8tj2d2NrYqP7g7k= github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e h1:CHPYEbz71w8DqJ7DRIq+MXyCQsdibK08vdcQTY4ufas= +github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e/go.mod h1:6Xhs0ZlsRjXLIiSMLKafbZxML/j30pg9Z1priLuha5s= github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/test/docker/Dockerfile b/test/docker/Dockerfile index ad11856f..322707f0 100644 --- a/test/docker/Dockerfile +++ b/test/docker/Dockerfile @@ -1,4 +1,4 @@ -ARG GO_IMAGE=golang:1.20.14 +ARG GO_IMAGE=golang:1.21.10 FROM $GO_IMAGE # Copy SDK code into the container diff --git a/test/helpers.go b/test/helpers.go index f362be89..0fc05254 100644 --- a/test/helpers.go +++ b/test/helpers.go @@ -52,7 +52,7 @@ func mockHTTPResponsesInLoadedFromHelper(jsonfiles, directory string, status int responseRing.Value = json responseRing = responseRing.Next() } - mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { json := responseRing.Value.([]byte) if status > 0 { w.WriteHeader(status) @@ -67,7 +67,7 @@ var receivedMethod string var receivedPath string func mockServerRecordingRequestPaths() error { - mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mockServer = httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { receivedMethod = r.Method receivedPath = r.URL.String() })) From d7c8f22a4ac16dc515b731877339ed15cf332df6 Mon Sep 17 00:00:00 2001 From: gmalouf Date: Wed, 8 May 2024 19:36:44 +0000 Subject: [PATCH 8/8] bump up version to v2.5.0 --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43467b22..8e45f0e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +# v2.5.0 + + + +## What's Changed +### Bugfixes +* Fix: Fix indexer sync issue in cucumber tests by @jasonpaulos in https://github.com/algorand/go-algorand-sdk/pull/628 +* chore: fix function names by @tianzedavid in https://github.com/algorand/go-algorand-sdk/pull/632 +* Tests: Fix funding for cucumber tests by rotating sender accounts by @jasonpaulos in https://github.com/algorand/go-algorand-sdk/pull/630 +### New Features +* Build: Bump golang version to 1.21.10 by @gmalouf in https://github.com/algorand/go-algorand-sdk/pull/636 +### Enhancements +* Build: Bump go version for builds/workflows to 1.20.14 by @gmalouf in https://github.com/algorand/go-algorand-sdk/pull/629 +* Incentives: Add fields in block header for proposer and fees collected. by @jannotti in https://github.com/algorand/go-algorand-sdk/pull/617 +### Other +* Regenerate code with the latest specification file (ff2c7476) by @github-actions in https://github.com/algorand/go-algorand-sdk/pull/631 + +## New Contributors +* @jannotti made their first contribution in https://github.com/algorand/go-algorand-sdk/pull/617 +* @tianzedavid made their first contribution in https://github.com/algorand/go-algorand-sdk/pull/632 + +**Full Changelog**: https://github.com/algorand/go-algorand-sdk/compare/v2.4.0...v2.5.0 + # v2.4.0