Skip to content

Commit 19e60fc

Browse files
Adds Proof of Possession for Node Staking Keys (#457)
* add POP changes to a new branch * remove outdated todo comment * include old register node transaction for backwards compatibility * update SCO.17 name * fix test helper * fix another helper issue --------- Co-authored-by: Tarak Ben youssef <[email protected]>
1 parent 81b89f9 commit 19e60fc

28 files changed

+659
-105
lines changed

contracts/FlowIDTableStaking.cdc

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ access(all) contract FlowIDTableStaking {
122122
access(all) var networkingKey: String
123123
access(all) var stakingKey: String
124124

125-
/// TODO: Proof of Possession (PoP) of the staking private key
126-
127125
/// The total tokens that only this node currently has staked, not including delegators
128126
/// This value must always be above the minimum requirement to stay staked or accept delegators
129127
access(mapping Identity) var tokensStaked: @FlowToken.Vault
@@ -160,6 +158,7 @@ access(all) contract FlowIDTableStaking {
160158
networkingAddress: String,
161159
networkingKey: String,
162160
stakingKey: String,
161+
stakingKeyPoP: String,
163162
tokensCommitted: @{FungibleToken.Vault}
164163
) {
165164
pre {
@@ -180,13 +179,20 @@ access(all) contract FlowIDTableStaking {
180179
signatureAlgorithm: SignatureAlgorithm.BLS_BLS12_381
181180
)
182181

182+
// Verify the proof of possesion of the private staking key
183+
assert(
184+
stakeKey.verifyPoP(stakingKeyPoP.decodeHex()),
185+
message:
186+
"FlowIDTableStaking.NodeRecord.init: Cannot create node with ID "
187+
.concat(id).concat(". The Proof of Possession (").concat(stakingKeyPoP)
188+
.concat(") for the node's staking key (").concat(") is invalid")
189+
)
190+
183191
let netKey = PublicKey(
184192
publicKey: networkingKey.decodeHex(),
185193
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
186194
)
187195

188-
// TODO: Verify the provided Proof of Possession of the staking private key
189-
190196
self.id = id
191197
self.role = role
192198
self.networkingAddress = networkingAddress
@@ -1560,6 +1566,7 @@ access(all) contract FlowIDTableStaking {
15601566
networkingAddress: String,
15611567
networkingKey: String,
15621568
stakingKey: String,
1569+
stakingKeyPoP: String,
15631570
tokensCommitted: @{FungibleToken.Vault}): @NodeStaker
15641571
{
15651572
assert (
@@ -1572,6 +1579,7 @@ access(all) contract FlowIDTableStaking {
15721579
networkingAddress: networkingAddress,
15731580
networkingKey: networkingKey,
15741581
stakingKey: stakingKey,
1582+
stakingKeyPoP: stakingKeyPoP,
15751583
tokensCommitted: <-FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()))
15761584

15771585
let minimum = self.minimumStakeRequired[role]!

contracts/FlowStakingCollection.cdc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ access(all) contract FlowStakingCollection {
473473
networkingAddress: String,
474474
networkingKey: String,
475475
stakingKey: String,
476+
stakingKeyPoP: String,
476477
amount: UFix64,
477478
payer: auth(BorrowValue) &Account
478479
): auth(Storage, Capabilities, Contracts, Keys, Inbox) &Account? {
@@ -485,6 +486,7 @@ access(all) contract FlowStakingCollection {
485486
networkingAddress: networkingAddress,
486487
networkingKey: networkingKey,
487488
stakingKey: stakingKey,
489+
stakingKeyPoP: stakingKeyPoP,
488490
tokensCommitted: <-tokens
489491
)
490492

contracts/LockedTokens.cdc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,10 @@ access(all) contract LockedTokens {
203203
204204
/// Registers a new node operator with the Flow Staking contract
205205
/// and commits an initial amount of locked tokens to stake
206-
access(account) fun registerNode(nodeInfo: StakingProxy.NodeInfo, amount: UFix64) {
206+
access(account) fun registerNode(nodeInfo: StakingProxy.NodeInfo,
207+
stakingKeyPoP: String,
208+
amount: UFix64
209+
) {
207210
if let nodeStaker <- self.nodeStaker <- nil {
208211
let stakingInfo = FlowIDTableStaking.NodeInfo(nodeID: nodeStaker.id)
209212

@@ -219,7 +222,13 @@ access(all) contract LockedTokens {
219222

220223
let tokens <- vaultRef.withdraw(amount: amount)
221224

222-
let nodeStaker <- self.nodeStaker <- FlowIDTableStaking.addNodeRecord(id: nodeInfo.id, role: nodeInfo.role, networkingAddress: nodeInfo.networkingAddress, networkingKey: nodeInfo.networkingKey, stakingKey: nodeInfo.stakingKey, tokensCommitted: <-tokens)
225+
let nodeStaker <- self.nodeStaker <- FlowIDTableStaking.addNodeRecord(id: nodeInfo.id,
226+
role: nodeInfo.role,
227+
networkingAddress: nodeInfo.networkingAddress,
228+
networkingKey: nodeInfo.networkingKey,
229+
stakingKey: nodeInfo.stakingKey,
230+
stakingKeyPoP: stakingKeyPoP,
231+
tokensCommitted: <-tokens)
223232

224233
destroy nodeStaker
225234

@@ -400,9 +409,9 @@ access(all) contract LockedTokens {
400409

401410
/// The user calls this function if they want to register as a node operator
402411
/// They have to provide all the info for their node
403-
access(TokenOperations) fun createNodeStaker(nodeInfo: StakingProxy.NodeInfo, amount: UFix64) {
412+
access(TokenOperations) fun createNodeStaker(nodeInfo: StakingProxy.NodeInfo, stakingKeyPoP: String, amount: UFix64) {
404413

405-
self.borrowTokenManager().registerNode(nodeInfo: nodeInfo, amount: amount)
414+
self.borrowTokenManager().registerNode(nodeInfo: nodeInfo, stakingKeyPoP: stakingKeyPoP, amount: amount)
406415

407416
// Create a new staker proxy that can be accessed in transactions
408417
self.nodeStakerProxy = LockedNodeStakerProxy(tokenManager: self.tokenManager)

contracts/testContracts/TestFlowIDTableStaking.cdc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ access(all) contract FlowIDTableStaking {
253253
networkingAddress: String,
254254
networkingKey: String,
255255
stakingKey: String,
256+
stakingKeyPoP: String,
256257
tokensCommitted: @{FungibleToken.Vault}
257258
): @NodeStaker {
258259
destroy tokensCommitted

lib/go/contracts/internal/assets/assets.go

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/go/templates/cmd/manifest/manifest.go

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ func generateManifest(env templates.Environment) *manifest {
128128
}
129129

130130
sampleStakingKey := cadenceValue{
131-
cadence.String("9e9ae0d645fd5fd9050792e0b0daa82cc1686d9133afa0f81a784b375c42ae48567d1545e7a9e1965f2c1a32f73cf8575ebb7a967f6e4d104d2df78eb8be409135d12da0499b8a00771f642c1b9c49397f22b440439f036c3bdee82f5309dab3"),
131+
cadence.String("8dec36ed8a91e3e5d737b06434d94a8a561c7889495d6c7081cd5e123a42124415b9391c9b9aa165c2f71994bf9607cb0ea262ad162fec74146d1ebc482a33b9dad203d16a83bbfda89b3f6e1cd1d8fb2e704a162d259a0ac9f26bc8635d74f6"),
132+
}
133+
134+
sampleStakingKeyPoP := cadenceValue{
135+
cadence.String("828a68a2be392804044d85888100462702a422901da3269fb6512defabad07250aad24f232671e4ac8ae531f54e062fc"),
132136
}
133137

134138
sampleNullOptional := cadenceValue{
@@ -436,7 +440,7 @@ func generateManifest(env templates.Environment) *manifest {
436440
m.addTemplate(generateTemplate(
437441
"SCO.03", "Register Node",
438442
env,
439-
templates.GenerateCollectionRegisterNode,
443+
templates.GenerateCollectionRegisterNodeOld,
440444
[]argument{
441445
{
442446
Type: "String",
@@ -824,6 +828,74 @@ func generateManifest(env templates.Environment) *manifest {
824828
},
825829
))
826830

831+
m.addTemplate(generateTemplate(
832+
"SCO.17", "Register Node",
833+
env,
834+
templates.GenerateCollectionRegisterNode,
835+
[]argument{
836+
{
837+
Type: "String",
838+
Name: "id",
839+
Label: "Node ID",
840+
SampleValues: []cadenceValue{sampleNodeID},
841+
},
842+
{
843+
Type: "UInt8",
844+
Name: "role",
845+
Label: "Node Role",
846+
SampleValues: []cadenceValue{sampleNodeRole},
847+
},
848+
{
849+
Type: "String",
850+
Name: "networkingAddress",
851+
Label: "Networking Address",
852+
SampleValues: []cadenceValue{sampleNetworkingAddress},
853+
},
854+
{
855+
Type: "String",
856+
Name: "networkingKey",
857+
Label: "Networking Key",
858+
SampleValues: []cadenceValue{sampleNetworkingKey},
859+
},
860+
{
861+
Type: "String",
862+
Name: "stakingKey",
863+
Label: "Staking Key",
864+
SampleValues: []cadenceValue{sampleStakingKey},
865+
},
866+
{
867+
Type: "String",
868+
Name: "stakingKeyPoP",
869+
Label: "Staking Key PoP",
870+
SampleValues: []cadenceValue{sampleStakingKeyPoP},
871+
},
872+
{
873+
Type: "UFix64",
874+
Name: "amount",
875+
Label: "Amount",
876+
SampleValues: []cadenceValue{sampleAmount},
877+
},
878+
{
879+
Type: "String",
880+
Name: "machineAccountKey",
881+
Label: "Machine Account Public Key",
882+
SampleValues: []cadenceValue{sampleKey},
883+
},
884+
{
885+
Type: "UInt8",
886+
Name: "machineAccountKeySignatureAlgorithm",
887+
Label: "Raw Value for Machine Account Signature Algorithm Enum",
888+
SampleValues: []cadenceValue{sampleSigAlgoEnumRawValue},
889+
},
890+
{
891+
Type: "UInt8",
892+
Name: "machineAccountKeyHashAlgorithm",
893+
Label: "Raw Value for Machine Account Hash Algorithm Enum",
894+
SampleValues: []cadenceValue{sampleHashAlgoEnumRawValue},
895+
},
896+
},
897+
))
898+
827899
return m
828900
}
829901

0 commit comments

Comments
 (0)