github.com/koko1123/flow-go-1@v0.29.6/model/flow/address_test.go (about)

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