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