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  }