Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
416c5eb
Add new Load and CongestionTax blockheader fields, Tip txn field
jannotti Jul 31, 2025
40f59d3
Properly raise congestion fees for the first txn in new block.
jannotti Dec 8, 2025
ec6871f
Test some checks that the transaction pool imposes on groups
jannotti Dec 8, 2025
6ab3295
Remove some unneeded casts
jannotti Dec 9, 2025
e64ef85
Merge remote-tracking branch 'upstream/master' into on-chain-congestion
jannotti Dec 9, 2025
cac9a39
Merge remote-tracking branch 'upstream/master' into on-chain-congestion
jannotti Dec 11, 2025
4b6ed64
CR from Pavel
jannotti Jan 8, 2026
6c3bc24
Clarifying comment
jannotti Jan 8, 2026
64784e1
Merge remote-tracking branch 'upstream/master' into on-chain-congestion
jannotti Jan 8, 2026
de78433
Show CongestionTax growing after upgrade
jannotti Jan 8, 2026
8a637df
typos
jannotti Jan 14, 2026
5efa37b
Check CongestionTax for correctness, regardless of load tracking
jannotti Jan 28, 2026
10ab154
missed named change
jannotti Jan 28, 2026
b301706
Merge remote-tracking branch 'upstream/master' into on-chain-congestion
jannotti Jan 28, 2026
13dd399
final conflict resolution
jannotti Jan 28, 2026
e3f75ab
ensure exactly correct congestion tax
jannotti Jan 29, 2026
18ee6a5
Show 0 congestion tax before consensus change
jannotti Jan 29, 2026
1a884e6
update ClassifyTxPoolError for on-chain-congestion
cce Jan 29, 2026
016caa2
Merge pull request #22 from cce/on-chain-congestion-fee-errors
jannotti Jan 30, 2026
7e561ce
Consensus flag tx.Tip
jannotti Jan 30, 2026
fbc33eb
Don't kick out free transactions when Tax is > 0
jannotti Jan 30, 2026
15debbe
partition test
jannotti Jan 30, 2026
e02d733
Correct some test error details
jannotti Jan 30, 2026
8ffce24
libgoal should use suggested tip
jannotti Jan 30, 2026
5a85fdf
Add a --tip flag to goal
jannotti Feb 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ generate:
msgp: $(patsubst %,%/msgp_gen.go,$(MSGP_GENERATE))

api:
make -C daemon/algod/api
$(MAKE) -j7 -C daemon/algod/api
Comment thread
jannotti marked this conversation as resolved.

logic:
make -C data/transactions/logic
$(MAKE) -C data/transactions/logic

MSGP := go run github.com/algorand/msgp@v1.1.62
%/msgp_gen.go: ALWAYS
Expand Down
586 changes: 362 additions & 224 deletions agreement/msgp_gen.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions agreement/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,9 @@ func verifyProposer(p unauthenticatedProposal, ledger LedgerReader) error {
if err != nil {
return fmt.Errorf("failed to determine incentive eligibility %w", err)
}
if !eligible && p.ProposerPayout().Raw > 0 {
return fmt.Errorf("proposer payout (%d) for ineligible Proposer %v",
p.ProposerPayout().Raw, p.Proposer())
if !eligible && !p.ProposerPayout().IsZero() {
return fmt.Errorf("proposer payout (%s) for ineligible Proposer %v",
p.ProposerPayout(), p.Proposer())
}

var alpha crypto.Digest
Expand Down
1 change: 0 additions & 1 deletion cmd/algod/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ var startupConfigCheckFields = []string{
"OutgoingMessageFilterBucketSize",
"ProposalAssemblyTime",
"ReservedFDs",
"TxPoolExponentialIncreaseFactor",
"TxPoolSize",
"VerifiedTranscationsCacheSize",
"EnableP2P",
Expand Down
40 changes: 8 additions & 32 deletions cmd/goal/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,10 +525,7 @@ var createAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
// Broadcast
Expand Down Expand Up @@ -605,10 +602,7 @@ var updateAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

// Broadcast or write transaction to file
if outFilename == "" {
Expand Down Expand Up @@ -675,10 +669,7 @@ var optInAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

// Broadcast or write transaction to file
if outFilename == "" {
Expand Down Expand Up @@ -745,10 +736,7 @@ var closeOutAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

// Broadcast or write transaction to file
if outFilename == "" {
Expand Down Expand Up @@ -815,10 +803,7 @@ var clearAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

// Broadcast or write transaction to file
if outFilename == "" {
Expand Down Expand Up @@ -884,10 +869,7 @@ var callAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

// Broadcast or write transaction to file
if outFilename == "" {
Expand Down Expand Up @@ -954,10 +936,7 @@ var deleteAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

// Broadcast or write transaction to file
if outFilename == "" {
Expand Down Expand Up @@ -1458,10 +1437,7 @@ var methodAppCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
appCallTxn.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&appCallTxn, cmd, client)

// Compile group
var txnGroup []transactions.Transaction
Expand Down
30 changes: 6 additions & 24 deletions cmd/goal/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,7 @@ var createAssetCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
Expand Down Expand Up @@ -370,10 +367,7 @@ var destroyAssetCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
Expand Down Expand Up @@ -463,10 +457,7 @@ var configAssetCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
Expand Down Expand Up @@ -550,10 +541,7 @@ var sendAssetCmd = &cobra.Command{
reportErrorf("Cannot construct transaction: %s", err)
}

explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
Expand Down Expand Up @@ -619,10 +607,7 @@ var freezeAssetCmd = &cobra.Command{
if err != nil {
reportErrorf("Cannot construct transaction: %s", err)
}
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
Expand Down Expand Up @@ -708,10 +693,7 @@ var optinAssetCmd = &cobra.Command{
reportErrorf("Cannot construct transaction: %s", err)
}

explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
tx.Fee = basics.MicroAlgos{Raw: fee}
}
applyFeeAndTip(&tx, cmd, client)

if outFilename == "" {
wh, pw := ensureWalletHandleMaybePassword(dataDir, walletName, true)
Expand Down
10 changes: 3 additions & 7 deletions cmd/goal/clerk.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,9 @@ var sendCmd = &cobra.Command{
payment.RekeyTo = rekeyTo
}

// ConstructPayment fills in the suggested fee when fee=0. But if the user actually used --fee=0 on the
// commandline, we ought to do what they asked (especially now that zero or low fees make sense in
// combination with other txns that cover the groups's fee.
explicitFee := cmd.Flags().Changed("fee")
if explicitFee {
payment.Fee = basics.MicroAlgos{Raw: fee}
}
// Apply fee and tip based on command-line flags.
// ConstructPayment fills in suggested fee/tip when neither is specified.
applyFeeAndTip(&payment, cmd, client)

var authAddr basics.Address
if signerAddress != "" {
Expand Down
34 changes: 34 additions & 0 deletions cmd/goal/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (

cmdutil "github.com/algorand/go-algorand/cmd/util"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/libgoal"
)

const (
Expand All @@ -42,6 +44,7 @@ var numValidRounds basics.Round // also used in account and asset

var (
fee uint64
tip uint64
outFilename string
sign bool
noteBase64 string
Expand All @@ -56,6 +59,7 @@ var dumpForDryrunFormat cmdutil.CobraStringValue = *cmdutil.MakeCobraStringValue

func addTxnFlags(cmd *cobra.Command) {
cmd.Flags().Uint64Var(&fee, "fee", 0, "The transaction fee (automatically determined by default), in microAlgos")
cmd.Flags().Uint64Var(&tip, "tip", 0, "The priority tip as a fractional multiplier (e.g., 100000 = 0.1 = 10%). If unset, Fee will be set to MinFee*(1 + tip)")
cmd.Flags().Uint64Var((*uint64)(&firstValid), "firstvalid", 0, "The first round where the transaction may be committed to the ledger")
cmd.Flags().Uint64Var((*uint64)(&numValidRounds), "validrounds", 0, "The number of rounds for which the transaction will be valid")
cmd.Flags().Uint64Var((*uint64)(&lastValid), "lastvalid", 0, "The last round where the transaction may be committed to the ledger")
Expand All @@ -70,3 +74,33 @@ func addTxnFlags(cmd *cobra.Command) {
cmd.Flags().StringSliceVar(&dumpForDryrunAccts, "dryrun-accounts", nil, "additional accounts to include into dryrun request obj")
cmd.Flags().StringVarP(&signerAddress, "signer", "S", "", "Address of key to sign with, if different from transaction \"from\" address due to rekeying")
}

// applyFeeAndTip applies the fee and tip to a transaction based on command-line flags.
// It handles four cases:
// 1. Both --fee and --tip are set: use them as-is
// 2. Only --tip is set: calculate fee from tip (fee = minFee * (1 + tip))
// 3. Only --fee is set: use the explicit fee leave Tip as is
// 4. Neither is set: transaction already has suggested fee and tip from construction
func applyFeeAndTip(tx *transactions.Transaction, cmd *cobra.Command, client libgoal.Client) {
explicitFee := cmd.Flags().Changed("fee")
explicitTip := cmd.Flags().Changed("tip")

switch {
case explicitFee && explicitTip:
tx.Fee = basics.MicroAlgos{Raw: fee}
tx.Tip = basics.Micros(tip)
case explicitTip:
params, err := client.SuggestedParams()
if err != nil {
reportErrorf("Error getting suggested params: %v", err)
}
baseFee := basics.MicroAlgos{Raw: params.MinFee}
calculatedFee, _ := baseFee.MulMicros(basics.AddSaturate(1e6, basics.Micros(tip)))
tx.Fee = calculatedFee
tx.Tip = basics.Micros(tip)
case explicitFee:
tx.Fee = basics.MicroAlgos{Raw: fee}
default:
// Neither is set, transaction construction already filled in suggested fee and tip
}
}
22 changes: 15 additions & 7 deletions config/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,6 @@ type ConsensusParams struct {
// a way of making the spender subsidize the cost of storing this transaction.
MinTxnFee uint64

// EnableFeePooling specifies that the sum of the fees in a
// group must exceed one MinTxnFee per Txn, rather than check that
// each Txn has a MinFee.
EnableFeePooling bool

Comment thread
gmalouf marked this conversation as resolved.
// EnableAppCostPooling specifies that the sum of fees for application calls
// in a group is checked against the sum of the budget for application calls,
// rather than check each individual app call is within the budget.
Expand Down Expand Up @@ -580,6 +575,14 @@ type ConsensusParams struct {
// specify the current app. This parameter can be removed and assumed true
// after the first consensus release in which it is set true.
AllowZeroLocalAppRef bool

// LoadTracking enables header values that track Load that grows/shrinks
// when blocks are more/less than half full.
LoadTracking bool

// SupportTips indicates the tx.Tip field can be used to promise additional
// fees are included.
SupportTips bool
}

// ProposerPayoutRules puts several related consensus parameters in one place. The same
Expand Down Expand Up @@ -666,6 +669,11 @@ type BonusPlan struct {
DecayInterval uint64
}

// MinFee simply returns the MinTxnFee as a basics.MicroAlgos
func (proto ConsensusParams) MinFee() basics.MicroAlgos {
return basics.MicroAlgos{Raw: proto.MinTxnFee}
}

// EffectiveKeyDilution returns the key dilution for this account,
// returning the default key dilution if not explicitly specified.
func (proto ConsensusParams) EffectiveKeyDilution(kd uint64) uint64 {
Expand Down Expand Up @@ -1185,7 +1193,6 @@ func initConsensusProtocols() {
// "reachability" between accounts and creatables, so we
// retain 4 x 4 as worst case.

v28.EnableFeePooling = true
v28.EnableKeyregCoherencyCheck = true

Consensus[protocol.ConsensusV28] = v28
Expand Down Expand Up @@ -1462,10 +1469,11 @@ func initConsensusProtocols() {
vFuture.ApprovedUpgrades = map[protocol.ConsensusVersion]uint64{}

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

vFuture.AppSizeUpdates = true
vFuture.AllowZeroLocalAppRef = true
vFuture.EnforceAuthAddrSenderDiff = true
vFuture.LoadTracking = true
vFuture.SupportTips = true

Consensus[protocol.ConsensusFuture] = vFuture

Expand Down
2 changes: 1 addition & 1 deletion config/localTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ type Local struct {
// FallbackDNSResolverAddress defines the fallback DNS resolver address that would be used if the system resolver would fail to retrieve SRV records.
FallbackDNSResolverAddress string `version[0]:""`

// TxPoolExponentialIncreaseFactor exponential increase factor of transaction pool's fee threshold, should always be 2 in production.
// TxPoolExponentialIncreaseFactor is deprecated and unused.
TxPoolExponentialIncreaseFactor uint64 `version[0]:"2"`
Comment thread
jannotti marked this conversation as resolved.

// SuggestedFeeBlockHistory is deprecated and unused.
Expand Down
15 changes: 10 additions & 5 deletions daemon/algod/api/algod.oas2.json
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@
},
"/v2/accounts/{address}/transactions/pending": {
"get": {
"description": "Get the list of pending transactions by address, sorted by priority, in decreasing order, truncated at the end at MAX. If MAX = 0, returns all pending transactions.\n",
"description": "Get the list of pending transactions by address, sorted by priority, in decreasing order, truncated at the end at MAX. If MAX = 0, returns all pending transactions.",
"tags": ["public", "participating"],
"produces": ["application/json", "application/msgpack"],
"schemes": ["http"],
Expand Down Expand Up @@ -1323,7 +1323,7 @@
},
"/v2/transactions/pending": {
"get": {
"description": "Get the list of pending transactions, sorted by priority, in decreasing order, truncated at the end at MAX. If MAX = 0, returns all pending transactions.\n",
"description": "Get the list of pending transactions, sorted by priority, in decreasing order, truncated at the end at MAX. If MAX = 0, returns all pending transactions.",
"tags": ["public", "participating"],
"produces": ["application/json", "application/msgpack"],
"schemes": ["http"],
Expand Down Expand Up @@ -1367,7 +1367,7 @@
},
"/v2/transactions/pending/{txid}": {
"get": {
"description": "Given a transaction ID of a recently submitted transaction, it returns information about it. There are several cases when this might succeed:\n- transaction committed (committed round \u003e 0)\n- transaction still in the pool (committed round = 0, pool error = \"\")\n- transaction removed from pool due to error (committed round = 0, pool error != \"\")\nOr the transaction may have happened sufficiently long ago that the node no longer remembers it, and this will return an error.\n",
"description": "Given a transaction ID of a recently submitted transaction, it returns information about it. There are several cases when this might succeed:\n- transaction committed (committed round \u003e 0)\n- transaction still in the pool (committed round = 0, pool error = \"\")\n- transaction removed from pool due to error (committed round = 0, pool error != \"\")\nOr the transaction may have happened sufficiently long ago that the node no longer remembers it, and this will return an error.",
"tags": ["public", "participating"],
"produces": ["application/json", "application/msgpack"],
"schemes": ["http"],
Expand Down Expand Up @@ -4715,7 +4715,7 @@
"type": "string"
},
"fee": {
"description": "Fee is the suggested transaction fee\nFee is in units of micro-Algos per byte.\nFee may fall to zero but transactions must still have a fee of\nat least MinTxnFee for the current network protocol.",
"description": "Fee is deprecated. It used to express the per-byte fee escalation.",
Comment thread
jannotti marked this conversation as resolved.
"type": "integer",
"x-go-type": "uint64"
},
Expand All @@ -4734,9 +4734,14 @@
"x-go-type": "basics.Round"
},
"min-fee": {
"description": "The minimum transaction fee (not per byte) required for the\ntxn to validate for the current network protocol.",
"description": "The minimum transaction fee (not per byte) required for the txn to validate for the current network protocol.",
"type": "integer",
"x-go-type": "uint64"
},
"congestion-tax": {
"description": "The extra fee per transaction for algod to admit the transaction under the current congestion conditions. Expressed as fixed-point number with 6 digits of precision, transaction fees must be (1 + congestion-tax) * min-fee.",
"type": "integer",
"x-go-type": "basics.Micros"
}
}
}
Expand Down
Loading
Loading