Skip to content

Commit

Permalink
add test for removing lots of nodes during slot selection and not get…
Browse files Browse the repository at this point in the history
…ting out of bounds access
  • Loading branch information
joshuahannan committed Sep 24, 2024
1 parent 8f8fc0f commit 3ccea9c
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 1 deletion.
14 changes: 14 additions & 0 deletions lib/go/templates/idtable_staking_templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,3 +576,17 @@ func GenerateGetApprovedNodesScript(env Environment) []byte {

return []byte(ReplaceAddresses(code, env))
}

func GenerateEndStakingTestScript(env Environment) []byte {
code := `
import FlowIDTableStaking from "FlowIDTableStaking"
access(all) fun main() {
let acct = getAuthAccount<auth(BorrowValue) &Account>("FlowIDTableStaking")
let adminRef = acct.storage.borrow<&FlowIDTableStaking.Admin>(from: FlowIDTableStaking.StakingAdminStoragePath)
?? panic("Could not borrow reference to staking admin")
adminRef.endStakingAuction()
}`
return []byte(ReplaceAddresses(code, env))
}
134 changes: 133 additions & 1 deletion lib/go/test/flow_idtable_nodes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ func TestIDTableManyNodes(t *testing.T) {
})

approvedNodesDict := generateCadenceNodeDictionary(approvedNodesStringArray)

// End staking auction
t.Run("Should end staking auction, pay rewards, and move tokens", func(t *testing.T) {

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

}

func TestIDTableOutOfBoundsAccess(t *testing.T) {

t.Parallel()

b, adapter := newBlockchain(emulator.WithTransactionMaxGasLimit(10000000))

env := templates.Environment{
FungibleTokenAddress: emulatorFTAddress,
FlowTokenAddress: emulatorFlowTokenAddress,
BurnerAddress: emulatorServiceAccount,
StorageFeesAddress: emulatorServiceAccount,
}

accountKeys := test.AccountKeyGenerator()

// Create new keys for the ID table account
IDTableAccountKey, IDTableSigner := accountKeys.NewWithSigner()
idTableAddress, _ := deployStakingContract(t, b, IDTableAccountKey, IDTableSigner, &env, true, []uint64{10000, 10000, 10000, 10000, 10000})

env.IDTableAddress = idTableAddress.Hex()

var nodeAccountKey *flow.AccountKey
var nodeSigner crypto.Signer
var nodeAddress flow.Address

// Create a new node account for nodes
nodeAccountKey, nodeSigner = accountKeys.NewWithSigner()
nodeAddress, _ = adapter.CreateAccount(context.Background(), []*flow.AccountKey{nodeAccountKey}, nil)

approvedNodes := make([]cadence.Value, numberOfNodes)
approvedNodesStringArray := make([]string, numberOfNodes)
nodeRoles := make([]cadence.Value, numberOfNodes)
nodeNetworkingAddresses := make([]cadence.Value, numberOfNodes)
nodeNetworkingKeys := make([]cadence.Value, numberOfNodes)
nodeStakingKeys := make([]cadence.Value, numberOfNodes)
nodeStakingAmounts := make([]cadence.Value, numberOfNodes)
nodePaths := make([]cadence.Value, numberOfNodes)

totalMint := numberOfNodes * nodeMintAmount
mintAmount := fmt.Sprintf("%d.0", totalMint)

script := templates.GenerateMintFlowScript(env)
tx := createTxWithTemplateAndAuthorizer(b, script, b.ServiceKey().Address)
_ = tx.AddArgument(cadence.NewAddress(nodeAddress))
_ = tx.AddArgument(CadenceUFix64(mintAmount))

signAndSubmit(
t, b, tx,
[]flow.Address{},
[]crypto.Signer{},
false,
)

tx = flow.NewTransaction().
SetScript(templates.GenerateStartStakingScript(env)).
SetGasLimit(9999).
SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber).
SetPayer(b.ServiceKey().Address).
AddAuthorizer(idTableAddress)

signAndSubmit(
t, b, tx,
[]flow.Address{idTableAddress},
[]crypto.Signer{IDTableSigner},
false,
)

t.Run("Should be able to create many valid Node structs", func(t *testing.T) {

for i := 0; i < numberOfNodes; i++ {

id := fmt.Sprintf("%064d", i)

approvedNodes[i] = CadenceString(id)
approvedNodesStringArray[i] = id

nodeRoles[i] = cadence.NewUInt8(uint8((i % 4) + 1))

networkingAddress := fmt.Sprintf("%0128d", i)

nodeNetworkingAddresses[i] = CadenceString(networkingAddress)

_, stakingKey, _, networkingKey := generateKeysForNodeRegistration(t)

nodeNetworkingKeys[i] = CadenceString(networkingKey)

nodeStakingKeys[i] = CadenceString(stakingKey)

tokenAmount, err := cadence.NewUFix64("1500000.0")
require.NoError(t, err)

nodeStakingAmounts[i] = tokenAmount
nodePaths[i] = cadence.Path{Domain: common.PathDomainStorage, Identifier: fmt.Sprintf("node%06d", i)}

}

assertCandidateLimitsEquals(t, b, env, []uint64{10000, 10000, 10000, 10000, 10000})

tx := flow.NewTransaction().
SetScript(templates.GenerateRegisterManyNodesScript(env)).
SetGasLimit(5000000).
SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber).
SetPayer(b.ServiceKey().Address).
AddAuthorizer(nodeAddress)

tx.AddArgument(cadence.NewArray(approvedNodes))
tx.AddArgument(cadence.NewArray(nodeRoles))
tx.AddArgument(cadence.NewArray(nodeNetworkingAddresses))
tx.AddArgument(cadence.NewArray(nodeNetworkingKeys))
tx.AddArgument(cadence.NewArray(nodeStakingKeys))
tx.AddArgument(cadence.NewArray(nodeStakingAmounts))
tx.AddArgument(cadence.NewArray(nodePaths))

signAndSubmit(
t, b, tx,
[]flow.Address{nodeAddress},
[]crypto.Signer{nodeSigner},
false,
)
})

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) {

setNodeRoleSlotLimits(t, b, env, idTableAddress, IDTableSigner, [5]uint16{5, 5, 5, 5, 2})

scriptResult, err := b.ExecuteScript(templates.GenerateEndStakingTestScript(env), nil)
require.NoError(t, err)
if !assert.True(t, scriptResult.Succeeded()) {
t.Log(scriptResult.Error.Error())
}
})
}

func TestIDTableUnstakeAllManyDelegators(t *testing.T) {

t.Parallel()
Expand Down

0 comments on commit 3ccea9c

Please sign in to comment.