@@ -160,6 +160,7 @@ pub contract FlowIDTableStaking {
160
160
) {
161
161
pre {
162
162
id.length == 64 : " Node ID length must be 32 bytes (64 hex characters)"
163
+ FlowIDTableStaking.isValidNodeID (id): " The node ID must have only numbers and lowercase hex characters"
163
164
FlowIDTableStaking.nodes[id] == nil : " The ID cannot already exist in the record"
164
165
role > = UInt8 (1 ) && role < = UInt8 (5 ): " The role must be 1, 2, 3, 4, or 5"
165
166
networkingAddress.length > 0 && networkingAddress.length < = 510 : " The networkingAddress must be less than 255 bytes (510 hex characters)"
@@ -728,6 +729,15 @@ pub contract FlowIDTableStaking {
728
729
return <- node
729
730
}
730
731
732
+ /// Sets a list of approved node IDs for the next epoch
733
+ /// Nodes not on this list will be unstaked at the end of the staking auction
734
+ /// and not considered to be a proposed/staked node
735
+ pub fun setApprovedList (_ nodeIDs : [String ]) {
736
+ let list = FlowIDTableStaking.account.load< [String]> (from : / storage/ idTableApproveList)
737
+
738
+ FlowIDTableStaking.account.save< [String]> (nodeIDs, to: / storage/ idTableApproveList)
739
+ }
740
+
731
741
/// Starts the staking auction, the period when nodes and delegators
732
742
/// are allowed to perform staking related operations
733
743
pub fun startStakingAuction () {
@@ -737,7 +747,13 @@ pub contract FlowIDTableStaking {
737
747
738
748
/// Ends the staking Auction by removing any unapproved nodes
739
749
/// and setting stakingEnabled to false
740
- pub fun endStakingAuction (approvedNodeIDs : {String : Bool }) {
750
+ pub fun endStakingAuction () {
751
+ let approvedList = FlowIDTableStaking.getApprovedList ()
752
+ let approvedNodeIDs : {String : Bool } = {}
753
+ for id in approvedList {
754
+ approvedNodeIDs[id] = true
755
+ }
756
+
741
757
self .removeUnapprovedNodes (approvedNodeIDs : approvedNodeIDs)
742
758
743
759
FlowIDTableStaking.account.load< Bool> (from : / storage/ stakingEnabled)
@@ -945,6 +961,9 @@ pub contract FlowIDTableStaking {
945
961
// Start the new epoch's staking auction
946
962
self .startStakingAuction ()
947
963
964
+ // Set the current Epoch node list
965
+ FlowIDTableStaking.setCurrentNodeList (FlowIDTableStaking.getApprovedList ())
966
+
948
967
// Indicates that the tokens have moved and the epoch has ended
949
968
// Tells what the new reward payout will be. The new payout is calculated and changed
950
969
// before this method is executed and will not be changed for the rest of the epoch
@@ -1067,21 +1086,50 @@ pub contract FlowIDTableStaking {
1067
1086
self .account.save (claimedDictionary, to : path)
1068
1087
}
1069
1088
1089
+ /// Sets a list of approved node IDs for the current epoch
1090
+ access (contract) fun setCurrentNodeList (_ nodeIDs : [String ]) {
1091
+ let list = self .account.load< [String]> (from : / storage/ idTableCurrentList)
1092
+
1093
+ self .account.save< [String]> (nodeIDs, to: / storage/ idTableCurrentList)
1094
+ }
1095
+
1096
+ /// Checks if the given string has all numbers or lowercase hex characters
1097
+ /// Used to ensure that there are no duplicate node IDs
1098
+ pub fun isValidNodeID (_ input : String ): Bool {
1099
+ let byteVersion = input.utf8
1100
+
1101
+ for character in byteVersion {
1102
+ if ((character < 48 ) || (character > 57 && character < 97 ) || (character > 102 )) {
1103
+ return false
1104
+ }
1105
+ }
1106
+
1107
+ return true
1108
+ }
1109
+
1070
1110
/// Indicates if the staking auction is currently enabled
1071
1111
pub fun stakingEnabled (): Bool {
1072
1112
return self .account.copy< Bool> (from : / storage/ stakingEnabled) ?? false
1073
1113
}
1074
1114
1075
- /// Gets an array of the node IDs that are proposed for the next epoch
1115
+ /// Gets an array of the node IDs that are proposed and approved for the next epoch
1076
1116
pub fun getProposedNodeIDs (): [String ] {
1077
1117
var proposedNodes : [String ] = []
1078
1118
1119
+ let approvedList = FlowIDTableStaking.getApprovedList ()
1120
+ let approvedNodeIDs : {String : Bool } = {}
1121
+ for id in approvedList {
1122
+ approvedNodeIDs[id] = true
1123
+ }
1124
+
1079
1125
for nodeID in FlowIDTableStaking.getNodeIDs () {
1080
1126
let nodeRecord = FlowIDTableStaking.borrowNodeRecord (nodeID)
1127
+ let approved = approvedNodeIDs[nodeID] ?? false
1081
1128
1082
1129
// To be considered proposed, a node has to have tokens staked + committed equal or above the minimum
1083
1130
// Access nodes have a minimum of 0, so they need to be strictly greater than zero to be considered proposed
1084
1131
if self .isGreaterThanMinimumForRole (numTokens : self .NodeInfo (nodeID : nodeRecord.id).totalCommittedWithoutDelegators (), role : nodeRecord.role)
1132
+ && approved
1085
1133
{
1086
1134
proposedNodes.append (nodeID)
1087
1135
}
@@ -1096,12 +1144,21 @@ pub contract FlowIDTableStaking {
1096
1144
pub fun getStakedNodeIDs (): [String ] {
1097
1145
var stakedNodes : [String ] = []
1098
1146
1147
+ let currentList = self .account.copy< [String]> (from : / storage/ idTableCurrentList)
1148
+ ?? panic (" Could not get current list" )
1149
+ let currentNodeIDs : {String : Bool } = {}
1150
+ for id in currentList {
1151
+ currentNodeIDs[id] = true
1152
+ }
1153
+
1099
1154
for nodeID in FlowIDTableStaking.getNodeIDs () {
1100
1155
let nodeRecord = FlowIDTableStaking.borrowNodeRecord (nodeID)
1156
+ let current = currentNodeIDs[nodeID] ?? false
1101
1157
1102
1158
// To be considered staked, a node has to have tokens staked equal or above the minimum
1103
1159
// Access nodes have a minimum of 0, so they need to be strictly greater than zero to be considered staked
1104
1160
if self .isGreaterThanMinimumForRole (numTokens : nodeRecord.tokensStaked.balance, role : nodeRecord.role)
1161
+ && current
1105
1162
{
1106
1163
stakedNodes.append (nodeID)
1107
1164
}
@@ -1142,6 +1199,12 @@ pub contract FlowIDTableStaking {
1142
1199
return claimedDictionary[key] ?? false
1143
1200
}
1144
1201
1202
+ /// Returns the list of approved node IDs that the admin has set
1203
+ pub fun getApprovedList (): [String ] {
1204
+ return self .account.copy< [String]> (from : / storage/ idTableApproveList)
1205
+ ?? panic (" could not get approved list" )
1206
+ }
1207
+
1145
1208
/// Gets the minimum stake requirements for all the node types
1146
1209
pub fun getMinimumStakeRequirements (): {UInt8 : UFix64 } {
1147
1210
return self .minimumStakeRequired
@@ -1203,6 +1266,10 @@ pub contract FlowIDTableStaking {
1203
1266
self .nodeDelegatingRewardCut = rewardCut
1204
1267
self .rewardRatios = {UInt8 (1 ): 0 .168 , UInt8 (2 ): 0 .518 , UInt8 (3 ): 0 .078 , UInt8 (4 ): 0 .236 , UInt8 (5 ): 0 .0 }
1205
1268
1269
+ let list : [String ] = []
1270
+ self .setCurrentNodeList (list)
1271
+ self .account.save< [String]> (list, to: / storage/ idTableApproveList)
1272
+
1206
1273
self .account.save (<- create Admin (), to : self .StakingAdminStoragePath)
1207
1274
}
1208
1275
}
0 commit comments