Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit f424ed4

Browse files
authored
Merge pull request #976 from iotaledger/fix/genesis-snapshot-underflow
Fix potential underflow in genesis snapshot generation
2 parents be93026 + ce479a8 commit f424ed4

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

Diff for: pkg/tests/validator_test.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
// Supply for the test with faster slot duration and slots per epoch.
2222
const SUPPLY = iotago.BaseToken(1_813_620_509_061_365)
2323

24-
func setupValidatorTestsuite(t *testing.T, walletOpts ...options.Option[testsuite.WalletOptions]) *testsuite.TestSuite {
24+
func setupValidatorTestsuiteWithStake(t *testing.T, validator1Balance iotago.BaseToken, validator2Balance iotago.BaseToken, walletOpts ...options.Option[testsuite.WalletOptions]) *testsuite.TestSuite {
2525
var slotDuration uint8 = 5
2626
var slotsPerEpochExponent uint8 = 5
2727
var validationBlocksPerSlot uint8 = 5
@@ -54,13 +54,13 @@ func setupValidatorTestsuite(t *testing.T, walletOpts ...options.Option[testsuit
5454
// Add validator nodes to the network. This will add validator accounts to the snapshot.
5555
vnode1 := ts.AddValidatorNode("node1", append(
5656
[]options.Option[testsuite.WalletOptions]{
57-
testsuite.WithWalletAmount(20_000_000),
57+
testsuite.WithWalletAmount(validator1Balance),
5858
},
5959
walletOpts...,
6060
)...)
6161
vnode2 := ts.AddValidatorNode("node2", append(
6262
[]options.Option[testsuite.WalletOptions]{
63-
testsuite.WithWalletAmount(25_000_000),
63+
testsuite.WithWalletAmount(validator2Balance),
6464
},
6565
walletOpts...,
6666
)...)
@@ -82,6 +82,10 @@ func setupValidatorTestsuite(t *testing.T, walletOpts ...options.Option[testsuit
8282
return ts
8383
}
8484

85+
func setupValidatorTestsuite(t *testing.T, walletOpts ...options.Option[testsuite.WalletOptions]) *testsuite.TestSuite {
86+
return setupValidatorTestsuiteWithStake(t, 20_000_000, 25_000_000, walletOpts...)
87+
}
88+
8589
type EpochPerformanceMap = map[iotago.EpochIndex]uint64
8690
type ValidatorTest struct {
8791
ts *testsuite.TestSuite
@@ -137,9 +141,14 @@ func Test_Validator_PerfectIssuanceWithNonZeroFixedCost(t *testing.T) {
137141
}
138142

139143
func Test_Validator_PerfectIssuanceWithHugeStake(t *testing.T) {
140-
// This gives both validators the max supply as stake, which is unrealistic,
144+
// This gives one validator almost the max supply as stake, which is unrealistic,
141145
// but is supposed to test if one validator with a huge stake causes an overflow in the rewards calculation.
142-
ts := setupValidatorTestsuite(t, testsuite.WithWalletAmount(SUPPLY))
146+
var validator1Balance iotago.BaseToken = 25_000_000
147+
var otherAccountBalance iotago.BaseToken = 31_700
148+
var genesisOutputBalance iotago.BaseToken = 14_100
149+
var validator2Balance iotago.BaseToken = SUPPLY - validator1Balance - otherAccountBalance - genesisOutputBalance
150+
151+
ts := setupValidatorTestsuiteWithStake(t, iotago.BaseToken(validator1Balance), validator2Balance)
143152
defer ts.Shutdown()
144153

145154
validationBlocksPerSlot := ts.API.ProtocolParameters().ValidationBlocksPerSlot()

Diff for: pkg/testsuite/snapshotcreator/snapshotcreator.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package snapshotcreator
33
import (
44
"os"
55

6+
"github.com/iotaledger/hive.go/core/safemath"
67
"github.com/iotaledger/hive.go/ierrors"
78
"github.com/iotaledger/hive.go/lo"
89
"github.com/iotaledger/hive.go/log"
@@ -137,12 +138,24 @@ func CreateSnapshot(opts ...options.Option[Options]) error {
137138
return accumulator + details.Amount
138139
}, iotago.BaseToken(0))
139140

141+
supplyMinusAccounts, err := safemath.SafeSub(opt.ProtocolParameters.TokenSupply(), totalAccountAmount)
142+
if err != nil {
143+
return ierrors.Wrapf(err, "failed to calculate genesis output balance, remaining funds: %d, needed account funds: %d", opt.ProtocolParameters.TokenSupply(), totalAccountAmount)
144+
}
145+
146+
genesisOutputBalance, err := safemath.SafeSub(supplyMinusAccounts, totalBasicOutputAmount)
147+
if err != nil {
148+
return ierrors.Wrapf(err, "failed to calculate genesis output balance, remaining funds: %d, needed basic output funds: %d", supplyMinusAccounts, totalBasicOutputAmount)
149+
}
150+
140151
var genesisTransactionOutputs iotago.TxEssenceOutputs
141-
genesisOutput, err := createGenesisOutput(api, opt.ProtocolParameters.TokenSupply()-totalAccountAmount-totalBasicOutputAmount, iotago.MaxMana/100, opt.GenesisKeyManager)
152+
genesisOutput, err := createGenesisOutput(api, genesisOutputBalance, iotago.MaxMana/100, opt.GenesisKeyManager)
142153
if err != nil {
143154
return ierrors.Wrap(err, "failed to create genesis outputs")
144155
}
145-
genesisTransactionOutputs = append(genesisTransactionOutputs, genesisOutput)
156+
if genesisOutput != nil {
157+
genesisTransactionOutputs = append(genesisTransactionOutputs, genesisOutput)
158+
}
146159

147160
accountOutputs, err := createGenesisAccounts(api, opt.Accounts)
148161
if err != nil {

0 commit comments

Comments
 (0)