github.com/onflow/flow-go@v0.33.17/model/flow/address_test.go (about) 1 package flow 2 3 import ( 4 "encoding/json" 5 "math/bits" 6 "math/rand" 7 "testing" 8 9 "github.com/onflow/cadence" 10 "github.com/onflow/cadence/runtime/common" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 type addressWrapper struct { 17 Address Address 18 } 19 20 func TestConvertAddress(t *testing.T) { 21 expected := BytesToAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8}) 22 cadenceAddress := cadence.BytesToAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8}) 23 runtimeAddress := common.MustBytesToAddress([]byte{1, 2, 3, 4, 5, 6, 7, 8}) 24 25 assert.NotEqual(t, cadenceAddress, runtimeAddress) 26 27 assert.Equal(t, expected, ConvertAddress(cadenceAddress)) 28 assert.Equal(t, expected, ConvertAddress(runtimeAddress)) 29 } 30 31 func TestBytesToAddress(t *testing.T) { 32 type testCase struct { 33 expected string 34 value string 35 } 36 37 for _, test := range []testCase{ 38 {string([]byte{0, 0, 0, 0, 0, 0, 0, 0}), ""}, 39 {string([]byte{0, 0, 0, 0}) + "1234", "1234"}, 40 {"12345678", "12345678"}, 41 {"12345678", "trim12345678"}, 42 } { 43 address := BytesToAddress([]byte(test.value)) 44 assert.Equal(t, test.expected, string(address[:])) 45 } 46 } 47 48 func TestHexToAddress(t *testing.T) { 49 50 type testCase struct { 51 literal string 52 value []byte 53 } 54 55 for _, test := range []testCase{ 56 {"123", []byte{0x1, 0x23}}, 57 {"1", []byte{0x1}}, 58 // leading zero 59 {"01", []byte{0x1}}, 60 {"001", []byte{0x1}}, 61 {"0001", []byte{0x1}}, 62 } { 63 64 expected := BytesToAddress(test.value) 65 66 assert.Equal(t, expected, HexToAddress(test.literal)) 67 assert.Equal(t, expected, HexToAddress("0x"+test.literal)) 68 } 69 } 70 71 func TestAddressJSON(t *testing.T) { 72 addr := Mainnet.Chain().ServiceAddress() 73 data, err := json.Marshal(addressWrapper{Address: addr}) 74 require.Nil(t, err) 75 76 t.Log(string(data)) 77 78 var out addressWrapper 79 err = json.Unmarshal(data, &out) 80 require.Nil(t, err) 81 assert.Equal(t, addr, out.Address) 82 } 83 84 func TestShort(t *testing.T) { 85 type testcase struct { 86 addr Address 87 expected string 88 } 89 90 cases := []testcase{ 91 { 92 addr: Mainnet.Chain().ServiceAddress(), 93 expected: Mainnet.Chain().ServiceAddress().Hex(), 94 }, 95 { 96 addr: HexToAddress("0000000002"), 97 expected: "02", 98 }, 99 { 100 addr: HexToAddress("1f10"), 101 expected: "1f10", 102 }, 103 { 104 addr: HexToAddress("0f10"), 105 expected: "0f10", 106 }, 107 } 108 109 for _, c := range cases { 110 assert.Equal(t, c.addr.Short(), c.expected) 111 } 112 } 113 114 func TestAccountAddress(t *testing.T) { 115 t.Run("address constants", testAddressConstants) 116 t.Run("address generation", testAddressGeneration) 117 t.Run("chain address intersections", testAddressesIntersection) 118 t.Run("index from address", testIndexFromAddress) 119 } 120 121 func testAddressConstants(t *testing.T) { 122 // check n and k fit in 8 and 6 bytes 123 assert.LessOrEqual(t, linearCodeN, 8*8) 124 assert.LessOrEqual(t, linearCodeK, 6*8) 125 126 // Test addresses for all type of networks 127 chainIDs := []ChainID{ 128 Mainnet, 129 Testnet, 130 Emulator, 131 Sandboxnet, 132 } 133 134 for _, chainID := range chainIDs { 135 136 chain := chainID.Chain() 137 if chainID != Emulator { 138 // check the Zero and Root constants 139 expected := uint64ToAddress(uint64(chainID.getChainCodeWord())) 140 141 assert.Equal(t, chain.zeroAddress(), expected) 142 expected = uint64ToAddress(generatorMatrixRows[0] ^ uint64(chainID.getChainCodeWord())) 143 assert.Equal(t, chain.ServiceAddress(), expected) 144 } 145 146 // check the transition from account zero to root 147 state := chain.NewAddressGenerator() 148 address, err := state.NextAddress() 149 require.NoError(t, err) 150 assert.Equal(t, address, chain.ServiceAddress()) 151 152 // check high state values: generation should fail for high value states 153 state = chain.newAddressGeneratorAtIndex(maxIndex - 1) 154 _, err = state.NextAddress() 155 assert.NoError(t, err) 156 _, err = state.NextAddress() 157 assert.Error(t, err) 158 159 // check zeroAddress() is an invalid address 160 z := chain.zeroAddress() 161 check := chain.IsValid(z) 162 assert.False(t, check, "should be invalid") 163 } 164 } 165 166 const invalidCodeWord = uint64(0xab2ae42382900010) 167 168 func testAddressGeneration(t *testing.T) { 169 // loops in each test 170 const loop = 50 171 172 // Test addresses for all type of networks 173 chainIDs := []ChainID{ 174 Mainnet, 175 Testnet, 176 Emulator, 177 Sandboxnet, 178 } 179 180 for _, chainID := range chainIDs { 181 182 chain := chainID.Chain() 183 184 // sanity check of NextAddress function consistency 185 state := chain.NewAddressGenerator() 186 expectedIndex := uint64(0) 187 for i := 0; i < loop; i++ { 188 expectedIndex++ 189 address, err := state.NextAddress() 190 require.NoError(t, err) 191 expectedAddress, err := chain.AddressAtIndex(expectedIndex) 192 require.NoError(t, err) 193 assert.Equal(t, address, expectedAddress) 194 require.Equal(t, state.CurrentAddress(), expectedAddress) 195 } 196 197 // sanity check of addresses weights in Flow. 198 // All addresses hamming weights must be less than d. 199 // this is only a sanity check of the implementation and not an exhaustive proof 200 if chainID == Mainnet { 201 r := uint64(rand.Intn(maxIndex - loop)) 202 state = chain.newAddressGeneratorAtIndex(r) 203 for i := 0; i < loop; i++ { 204 address, err := state.NextAddress() 205 require.NoError(t, err) 206 weight := bits.OnesCount64(address.uint64()) 207 assert.LessOrEqual(t, linearCodeD, weight) 208 } 209 } 210 211 if chainID == Mainnet { 212 213 // sanity check of address distances. 214 // All distances between any two addresses must be less than d. 215 // this is only a sanity check of the implementation and not an exhaustive proof 216 r := uint64(rand.Intn(maxIndex - loop - 1)) 217 state = chain.newAddressGeneratorAtIndex(r) 218 refAddress, err := state.NextAddress() 219 require.NoError(t, err) 220 for i := 0; i < loop; i++ { 221 address, err := state.NextAddress() 222 require.NoError(t, err) 223 distance := bits.OnesCount64(address.uint64() ^ refAddress.uint64()) 224 assert.LessOrEqual(t, linearCodeD, distance) 225 } 226 227 } 228 229 // sanity check of valid account addresses. 230 // All valid addresses must pass IsValid. 231 r := uint64(rand.Intn(maxIndex - loop)) 232 state = chain.newAddressGeneratorAtIndex(r) 233 for i := 0; i < loop; i++ { 234 address, err := state.NextAddress() 235 require.NoError(t, err) 236 check := chain.IsValid(address) 237 assert.True(t, check, "account address format should be valid") 238 } 239 240 // sanity check of invalid account addresses. 241 // All invalid addresses must fail IsValid. 242 invalidAddress := uint64ToAddress(invalidCodeWord) 243 check := chain.IsValid(invalidAddress) 244 assert.False(t, check, "account address format should be invalid") 245 r = uint64(rand.Intn(maxIndex - loop)) 246 247 state = chain.newAddressGeneratorAtIndex(r) 248 for i := 0; i < loop; i++ { 249 address, err := state.NextAddress() 250 require.NoError(t, err) 251 invalidAddress = uint64ToAddress(address.uint64() ^ invalidCodeWord) 252 check := chain.IsValid(invalidAddress) 253 assert.False(t, check, "account address format should be invalid") 254 } 255 } 256 } 257 258 func testAddressesIntersection(t *testing.T) { 259 // loops in each test 260 const loop = 25 261 262 // Test addresses for all type of networks 263 chainIDs := []ChainID{ 264 Mainnet, 265 Testnet, 266 Emulator, 267 Sandboxnet, 268 } 269 270 for _, chainID := range chainIDs { 271 272 chain := chainID.Chain() 273 274 // All valid test addresses must fail Flow Mainnet check 275 r := uint64(rand.Intn(maxIndex - loop)) 276 state := chain.newAddressGeneratorAtIndex(r) 277 for k := 0; k < loop; k++ { 278 address, err := state.NextAddress() 279 require.NoError(t, err) 280 for _, otherChain := range chainIDs { 281 if chainID != otherChain { 282 check := otherChain.Chain().IsValid(address) 283 assert.False(t, check, "test account address format should be invalid in Flow") 284 } else { 285 sameChainCheck := chain.IsValid(address) 286 require.True(t, sameChainCheck) 287 } 288 } 289 } 290 291 // sanity check: mainnet addresses must fail the test check 292 r = uint64(rand.Intn(maxIndex - loop)) 293 for k := 0; k < loop; k++ { 294 for _, otherChain := range chainIDs { 295 if chainID != otherChain { 296 invalidAddress, err := otherChain.Chain().newAddressGeneratorAtIndex(r).NextAddress() 297 require.NoError(t, err) 298 check := chain.IsValid(invalidAddress) 299 assert.False(t, check, "account address format should be invalid") 300 } 301 } 302 } 303 304 // sanity check of invalid account addresses in all networks 305 require.NotEqual(t, invalidCodeWord, uint64(0)) 306 invalidAddress := uint64ToAddress(invalidCodeWord) 307 check := chain.IsValid(invalidAddress) 308 assert.False(t, check, "account address format should be invalid") 309 r = uint64(rand.Intn(maxIndex - loop)) 310 311 state = chain.newAddressGeneratorAtIndex(r) 312 for k := 0; k < loop; k++ { 313 address, err := state.NextAddress() 314 require.NoError(t, err) 315 invalidAddress = uint64ToAddress(address.uint64() ^ invalidCodeWord) 316 317 // must fail test network check 318 check = chain.IsValid(invalidAddress) 319 assert.False(t, check, "account address format should be invalid") 320 } 321 } 322 } 323 324 func testIndexFromAddress(t *testing.T) { 325 // loops in each test 326 const loop = 50 327 328 // Test addresses for all type of networks 329 chains := []Chain{ 330 mainnet, 331 testnet, 332 emulator, 333 sandboxnet, 334 } 335 336 for _, chain := range chains { 337 for i := 0; i < loop; i++ { 338 // check the correctness of IndexFromAddress 339 340 // random valid index 341 r := uint64(rand.Intn(maxIndex)) + 1 342 // generate the address 343 address := chain.newAddressGeneratorAtIndex(r).CurrentAddress() 344 // extract the index and compare 345 index, err := chain.IndexFromAddress(address) 346 assert.NoError(t, err) // address should be valid 347 assert.Equal(t, r, index, "wrong extracted address %d, should be %d", index, r) 348 349 // check for invalid addresses 350 351 // alter one bit in the address to obtain an invalid address 352 address[0] ^= 1 353 _, err = chain.IndexFromAddress(address) 354 assert.Error(t, err) 355 } 356 // check the zero address error 357 _, err := chain.IndexFromAddress(chain.zeroAddress()) 358 assert.Error(t, err) 359 } 360 } 361 362 func TestUint48(t *testing.T) { 363 const loop = 50 364 // test consistensy of putUint48 and uint48 365 for i := 0; i < loop; i++ { 366 r := uint64(rand.Intn(1 << linearCodeK)) 367 b := make([]byte, addressIndexLength) 368 putUint48(b, r) 369 res := uint48(b) 370 assert.Equal(t, r, res) 371 } 372 }