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  }