github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/state/metadata_validator_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package state 5 6 import ( 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/MetalBlockchain/metalgo/codec" 13 "github.com/MetalBlockchain/metalgo/database" 14 "github.com/MetalBlockchain/metalgo/database/memdb" 15 "github.com/MetalBlockchain/metalgo/ids" 16 "github.com/MetalBlockchain/metalgo/utils/wrappers" 17 ) 18 19 func TestValidatorUptimes(t *testing.T) { 20 require := require.New(t) 21 state := newValidatorState() 22 23 // get non-existent uptime 24 nodeID := ids.GenerateTestNodeID() 25 subnetID := ids.GenerateTestID() 26 _, _, err := state.GetUptime(nodeID, subnetID) 27 require.ErrorIs(err, database.ErrNotFound) 28 29 // set non-existent uptime 30 err = state.SetUptime(nodeID, subnetID, 1, time.Now()) 31 require.ErrorIs(err, database.ErrNotFound) 32 33 testMetadata := &validatorMetadata{ 34 UpDuration: time.Hour, 35 lastUpdated: time.Now(), 36 } 37 // load uptime 38 state.LoadValidatorMetadata(nodeID, subnetID, testMetadata) 39 40 // get uptime 41 upDuration, lastUpdated, err := state.GetUptime(nodeID, subnetID) 42 require.NoError(err) 43 require.Equal(testMetadata.UpDuration, upDuration) 44 require.Equal(testMetadata.lastUpdated, lastUpdated) 45 46 // set uptime 47 newUpDuration := testMetadata.UpDuration + 1 48 newLastUpdated := testMetadata.lastUpdated.Add(time.Hour) 49 require.NoError(state.SetUptime(nodeID, subnetID, newUpDuration, newLastUpdated)) 50 51 // get new uptime 52 upDuration, lastUpdated, err = state.GetUptime(nodeID, subnetID) 53 require.NoError(err) 54 require.Equal(newUpDuration, upDuration) 55 require.Equal(newLastUpdated, lastUpdated) 56 57 // load uptime changes uptimes 58 newTestMetadata := &validatorMetadata{ 59 UpDuration: testMetadata.UpDuration + time.Hour, 60 lastUpdated: testMetadata.lastUpdated.Add(time.Hour), 61 } 62 state.LoadValidatorMetadata(nodeID, subnetID, newTestMetadata) 63 64 // get new uptime 65 upDuration, lastUpdated, err = state.GetUptime(nodeID, subnetID) 66 require.NoError(err) 67 require.Equal(newTestMetadata.UpDuration, upDuration) 68 require.Equal(newTestMetadata.lastUpdated, lastUpdated) 69 70 // delete uptime 71 state.DeleteValidatorMetadata(nodeID, subnetID) 72 73 // get deleted uptime 74 _, _, err = state.GetUptime(nodeID, subnetID) 75 require.ErrorIs(err, database.ErrNotFound) 76 } 77 78 func TestWriteValidatorMetadata(t *testing.T) { 79 require := require.New(t) 80 state := newValidatorState() 81 82 primaryDB := memdb.New() 83 subnetDB := memdb.New() 84 85 // write empty uptimes 86 require.NoError(state.WriteValidatorMetadata(primaryDB, subnetDB, CodecVersion1)) 87 88 // load uptime 89 nodeID := ids.GenerateTestNodeID() 90 subnetID := ids.GenerateTestID() 91 testUptimeReward := &validatorMetadata{ 92 UpDuration: time.Hour, 93 lastUpdated: time.Now(), 94 PotentialReward: 100, 95 txID: ids.GenerateTestID(), 96 } 97 state.LoadValidatorMetadata(nodeID, subnetID, testUptimeReward) 98 99 // write state, should not reflect to DB yet 100 require.NoError(state.WriteValidatorMetadata(primaryDB, subnetDB, CodecVersion1)) 101 require.False(primaryDB.Has(testUptimeReward.txID[:])) 102 require.False(subnetDB.Has(testUptimeReward.txID[:])) 103 104 // get uptime should still return the loaded value 105 upDuration, lastUpdated, err := state.GetUptime(nodeID, subnetID) 106 require.NoError(err) 107 require.Equal(testUptimeReward.UpDuration, upDuration) 108 require.Equal(testUptimeReward.lastUpdated, lastUpdated) 109 110 // update uptimes 111 newUpDuration := testUptimeReward.UpDuration + 1 112 newLastUpdated := testUptimeReward.lastUpdated.Add(time.Hour) 113 require.NoError(state.SetUptime(nodeID, subnetID, newUpDuration, newLastUpdated)) 114 115 // write uptimes, should reflect to subnet DB 116 require.NoError(state.WriteValidatorMetadata(primaryDB, subnetDB, CodecVersion1)) 117 require.False(primaryDB.Has(testUptimeReward.txID[:])) 118 require.True(subnetDB.Has(testUptimeReward.txID[:])) 119 } 120 121 func TestValidatorDelegateeRewards(t *testing.T) { 122 require := require.New(t) 123 state := newValidatorState() 124 125 // get non-existent delegatee reward 126 nodeID := ids.GenerateTestNodeID() 127 subnetID := ids.GenerateTestID() 128 _, err := state.GetDelegateeReward(subnetID, nodeID) 129 require.ErrorIs(err, database.ErrNotFound) 130 131 // set non-existent delegatee reward 132 err = state.SetDelegateeReward(subnetID, nodeID, 100000) 133 require.ErrorIs(err, database.ErrNotFound) 134 135 testMetadata := &validatorMetadata{ 136 PotentialDelegateeReward: 100000, 137 } 138 // load delegatee reward 139 state.LoadValidatorMetadata(nodeID, subnetID, testMetadata) 140 141 // get delegatee reward 142 delegateeReward, err := state.GetDelegateeReward(subnetID, nodeID) 143 require.NoError(err) 144 require.Equal(testMetadata.PotentialDelegateeReward, delegateeReward) 145 146 // set delegatee reward 147 newDelegateeReward := testMetadata.PotentialDelegateeReward + 100000 148 require.NoError(state.SetDelegateeReward(subnetID, nodeID, newDelegateeReward)) 149 150 // get new delegatee reward 151 delegateeReward, err = state.GetDelegateeReward(subnetID, nodeID) 152 require.NoError(err) 153 require.Equal(newDelegateeReward, delegateeReward) 154 155 // load delegatee reward changes 156 newTestMetadata := &validatorMetadata{ 157 PotentialDelegateeReward: testMetadata.PotentialDelegateeReward + 100000, 158 } 159 state.LoadValidatorMetadata(nodeID, subnetID, newTestMetadata) 160 161 // get new delegatee reward 162 delegateeReward, err = state.GetDelegateeReward(subnetID, nodeID) 163 require.NoError(err) 164 require.Equal(newTestMetadata.PotentialDelegateeReward, delegateeReward) 165 166 // delete delegatee reward 167 state.DeleteValidatorMetadata(nodeID, subnetID) 168 169 // get deleted delegatee reward 170 _, _, err = state.GetUptime(nodeID, subnetID) 171 require.ErrorIs(err, database.ErrNotFound) 172 } 173 174 func TestParseValidatorMetadata(t *testing.T) { 175 type test struct { 176 name string 177 bytes []byte 178 expected *validatorMetadata 179 expectedErr error 180 } 181 tests := []test{ 182 { 183 name: "nil", 184 bytes: nil, 185 expected: &validatorMetadata{ 186 lastUpdated: time.Unix(0, 0), 187 }, 188 expectedErr: nil, 189 }, 190 { 191 name: "nil", 192 bytes: []byte{}, 193 expected: &validatorMetadata{ 194 lastUpdated: time.Unix(0, 0), 195 }, 196 expectedErr: nil, 197 }, 198 { 199 name: "potential reward only", 200 bytes: []byte{ 201 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 202 }, 203 expected: &validatorMetadata{ 204 PotentialReward: 100000, 205 lastUpdated: time.Unix(0, 0), 206 }, 207 expectedErr: nil, 208 }, 209 { 210 name: "uptime + potential reward", 211 bytes: []byte{ 212 // codec version 213 0x00, 0x00, 214 // up duration 215 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x8D, 0x80, 216 // last updated 217 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xBB, 0xA0, 218 // potential reward 219 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 220 }, 221 expected: &validatorMetadata{ 222 UpDuration: 6000000, 223 LastUpdated: 900000, 224 PotentialReward: 100000, 225 lastUpdated: time.Unix(900000, 0), 226 }, 227 expectedErr: nil, 228 }, 229 { 230 name: "uptime + potential reward + potential delegatee reward", 231 bytes: []byte{ 232 // codec version 233 0x00, 0x00, 234 // up duration 235 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x8D, 0x80, 236 // last updated 237 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xBB, 0xA0, 238 // potential reward 239 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 240 // potential delegatee reward 241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x20, 242 }, 243 expected: &validatorMetadata{ 244 UpDuration: 6000000, 245 LastUpdated: 900000, 246 PotentialReward: 100000, 247 PotentialDelegateeReward: 20000, 248 lastUpdated: time.Unix(900000, 0), 249 }, 250 expectedErr: nil, 251 }, 252 { 253 name: "invalid codec version", 254 bytes: []byte{ 255 // codec version 256 0x00, 0x02, 257 // up duration 258 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x8D, 0x80, 259 // last updated 260 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xBB, 0xA0, 261 // potential reward 262 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 263 // potential delegatee reward 264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x20, 265 }, 266 expected: nil, 267 expectedErr: codec.ErrUnknownVersion, 268 }, 269 { 270 name: "short byte len", 271 bytes: []byte{ 272 // codec version 273 0x00, 0x00, 274 // up duration 275 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x8D, 0x80, 276 // last updated 277 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xBB, 0xA0, 278 // potential reward 279 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x86, 0xA0, 280 // potential delegatee reward 281 0x00, 0x00, 0x00, 0x00, 0x4E, 0x20, 282 }, 283 expected: nil, 284 expectedErr: wrappers.ErrInsufficientLength, 285 }, 286 } 287 for _, tt := range tests { 288 t.Run(tt.name, func(t *testing.T) { 289 require := require.New(t) 290 var metadata validatorMetadata 291 err := parseValidatorMetadata(tt.bytes, &metadata) 292 require.ErrorIs(err, tt.expectedErr) 293 if tt.expectedErr != nil { 294 return 295 } 296 require.Equal(tt.expected, &metadata) 297 }) 298 } 299 }