Skip to content

Commit 028f5a6

Browse files
committed
add test for removing lots of nodes during slot selection and not getting out of bounds access
1 parent 5f65eeb commit 028f5a6

File tree

2 files changed

+147
-1
lines changed

2 files changed

+147
-1
lines changed

lib/go/templates/idtable_staking_templates.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,17 @@ func GenerateGetApprovedNodesScript(env Environment) []byte {
576576

577577
return []byte(ReplaceAddresses(code, env))
578578
}
579+
580+
func GenerateEndStakingTestScript(env Environment) []byte {
581+
code := `
582+
import FlowIDTableStaking from "FlowIDTableStaking"
583+
584+
access(all) fun main() {
585+
let acct = getAuthAccount<auth(BorrowValue) &Account>("FlowIDTableStaking")
586+
let adminRef = acct.storage.borrow<&FlowIDTableStaking.Admin>(from: FlowIDTableStaking.StakingAdminStoragePath)
587+
?? panic("Could not borrow reference to staking admin")
588+
589+
adminRef.endStakingAuction()
590+
}`
591+
return []byte(ReplaceAddresses(code, env))
592+
}

lib/go/test/flow_idtable_nodes_test.go

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ func TestIDTableManyNodes(t *testing.T) {
204204
})
205205

206206
approvedNodesDict := generateCadenceNodeDictionary(approvedNodesStringArray)
207-
208207
// End staking auction
209208
t.Run("Should end staking auction, pay rewards, and move tokens", func(t *testing.T) {
210209

@@ -362,6 +361,139 @@ func TestIDTableManyNodes(t *testing.T) {
362361

363362
}
364363

364+
func TestIDTableOutOfBoundsAccess(t *testing.T) {
365+
366+
t.Parallel()
367+
368+
b, adapter := newBlockchain(emulator.WithTransactionMaxGasLimit(10000000))
369+
370+
env := templates.Environment{
371+
FungibleTokenAddress: emulatorFTAddress,
372+
FlowTokenAddress: emulatorFlowTokenAddress,
373+
BurnerAddress: emulatorServiceAccount,
374+
StorageFeesAddress: emulatorServiceAccount,
375+
}
376+
377+
accountKeys := test.AccountKeyGenerator()
378+
379+
// Create new keys for the ID table account
380+
IDTableAccountKey, IDTableSigner := accountKeys.NewWithSigner()
381+
idTableAddress, _ := deployStakingContract(t, b, IDTableAccountKey, IDTableSigner, &env, true, []uint64{10000, 10000, 10000, 10000, 10000})
382+
383+
env.IDTableAddress = idTableAddress.Hex()
384+
385+
var nodeAccountKey *flow.AccountKey
386+
var nodeSigner crypto.Signer
387+
var nodeAddress flow.Address
388+
389+
// Create a new node account for nodes
390+
nodeAccountKey, nodeSigner = accountKeys.NewWithSigner()
391+
nodeAddress, _ = adapter.CreateAccount(context.Background(), []*flow.AccountKey{nodeAccountKey}, nil)
392+
393+
approvedNodes := make([]cadence.Value, numberOfNodes)
394+
approvedNodesStringArray := make([]string, numberOfNodes)
395+
nodeRoles := make([]cadence.Value, numberOfNodes)
396+
nodeNetworkingAddresses := make([]cadence.Value, numberOfNodes)
397+
nodeNetworkingKeys := make([]cadence.Value, numberOfNodes)
398+
nodeStakingKeys := make([]cadence.Value, numberOfNodes)
399+
nodeStakingAmounts := make([]cadence.Value, numberOfNodes)
400+
nodePaths := make([]cadence.Value, numberOfNodes)
401+
402+
totalMint := numberOfNodes * nodeMintAmount
403+
mintAmount := fmt.Sprintf("%d.0", totalMint)
404+
405+
script := templates.GenerateMintFlowScript(env)
406+
tx := createTxWithTemplateAndAuthorizer(b, script, b.ServiceKey().Address)
407+
_ = tx.AddArgument(cadence.NewAddress(nodeAddress))
408+
_ = tx.AddArgument(CadenceUFix64(mintAmount))
409+
410+
signAndSubmit(
411+
t, b, tx,
412+
[]flow.Address{},
413+
[]crypto.Signer{},
414+
false,
415+
)
416+
417+
tx = flow.NewTransaction().
418+
SetScript(templates.GenerateStartStakingScript(env)).
419+
SetGasLimit(9999).
420+
SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber).
421+
SetPayer(b.ServiceKey().Address).
422+
AddAuthorizer(idTableAddress)
423+
424+
signAndSubmit(
425+
t, b, tx,
426+
[]flow.Address{idTableAddress},
427+
[]crypto.Signer{IDTableSigner},
428+
false,
429+
)
430+
431+
t.Run("Should be able to create many valid Node structs", func(t *testing.T) {
432+
433+
for i := 0; i < numberOfNodes; i++ {
434+
435+
id := fmt.Sprintf("%064d", i)
436+
437+
approvedNodes[i] = CadenceString(id)
438+
approvedNodesStringArray[i] = id
439+
440+
nodeRoles[i] = cadence.NewUInt8(uint8((i % 4) + 1))
441+
442+
networkingAddress := fmt.Sprintf("%0128d", i)
443+
444+
nodeNetworkingAddresses[i] = CadenceString(networkingAddress)
445+
446+
_, stakingKey, _, networkingKey := generateKeysForNodeRegistration(t)
447+
448+
nodeNetworkingKeys[i] = CadenceString(networkingKey)
449+
450+
nodeStakingKeys[i] = CadenceString(stakingKey)
451+
452+
tokenAmount, err := cadence.NewUFix64("1500000.0")
453+
require.NoError(t, err)
454+
455+
nodeStakingAmounts[i] = tokenAmount
456+
nodePaths[i] = cadence.Path{Domain: common.PathDomainStorage, Identifier: fmt.Sprintf("node%06d", i)}
457+
458+
}
459+
460+
assertCandidateLimitsEquals(t, b, env, []uint64{10000, 10000, 10000, 10000, 10000})
461+
462+
tx := flow.NewTransaction().
463+
SetScript(templates.GenerateRegisterManyNodesScript(env)).
464+
SetGasLimit(5000000).
465+
SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber).
466+
SetPayer(b.ServiceKey().Address).
467+
AddAuthorizer(nodeAddress)
468+
469+
tx.AddArgument(cadence.NewArray(approvedNodes))
470+
tx.AddArgument(cadence.NewArray(nodeRoles))
471+
tx.AddArgument(cadence.NewArray(nodeNetworkingAddresses))
472+
tx.AddArgument(cadence.NewArray(nodeNetworkingKeys))
473+
tx.AddArgument(cadence.NewArray(nodeStakingKeys))
474+
tx.AddArgument(cadence.NewArray(nodeStakingAmounts))
475+
tx.AddArgument(cadence.NewArray(nodePaths))
476+
477+
signAndSubmit(
478+
t, b, tx,
479+
[]flow.Address{nodeAddress},
480+
[]crypto.Signer{nodeSigner},
481+
false,
482+
)
483+
})
484+
485+
t.Run("Should end staking auction with no approved nodes which should not fail because of out of bounds array access", func(t *testing.T) {
486+
487+
setNodeRoleSlotLimits(t, b, env, idTableAddress, IDTableSigner, [5]uint16{5, 5, 5, 5, 2})
488+
489+
scriptResult, err := b.ExecuteScript(templates.GenerateEndStakingTestScript(env), nil)
490+
require.NoError(t, err)
491+
if !assert.True(t, scriptResult.Succeeded()) {
492+
t.Log(scriptResult.Error.Error())
493+
}
494+
})
495+
}
496+
365497
func TestIDTableUnstakeAllManyDelegators(t *testing.T) {
366498

367499
t.Parallel()

0 commit comments

Comments
 (0)