github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/acm/acmstate/state_cache_test.go (about)

     1  package acmstate
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hyperledger/burrow/acm"
     7  	"github.com/hyperledger/burrow/binary"
     8  	"github.com/hyperledger/burrow/crypto"
     9  	"github.com/hyperledger/burrow/execution/evm/asm"
    10  	"github.com/hyperledger/burrow/permission"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestStateCache_GetAccount(t *testing.T) {
    16  	// Build backend states for read and write
    17  	readBackend := testAccounts()
    18  	writeBackend := NewCache(NewMemoryState())
    19  	cache := NewCache(readBackend)
    20  
    21  	// Create account
    22  	acc := readBackend.Accounts[addressOf("acc1")]
    23  
    24  	// Get account from cache
    25  	accOut, err := cache.GetAccount(acc.Address)
    26  	require.NoError(t, err)
    27  	cache.UpdateAccount(accOut)
    28  
    29  	// Check that cache account matches original account
    30  	assert.True(t, acc.Equal(accOut), "accounts should be equal")
    31  
    32  	// Sync account to backend
    33  	err = cache.Sync(writeBackend)
    34  	require.NoError(t, err)
    35  
    36  	// Get account from backend
    37  	accOut, err = writeBackend.GetAccount(acc.Address)
    38  	require.NotNil(t, accOut)
    39  	assert.NoError(t, err)
    40  
    41  	// Check that backend account matches original account
    42  	assert.True(t, acc.Equal(accOut), "accounts should be equal")
    43  
    44  	accOut, err = cache.GetAccount(acc.Address)
    45  	require.NoError(t, err)
    46  	accOut.Balance = 100000
    47  	cache2 := NewCache(cache)
    48  	accOut2, err := cache2.GetAccount(acc.Address)
    49  	require.NoError(t, err)
    50  	assert.NotEqual(t, accOut2.Balance, accOut.Balance)
    51  }
    52  
    53  func TestStateCache_Miss(t *testing.T) {
    54  	readBackend := testAccounts()
    55  	cache := NewCache(readBackend)
    56  
    57  	acc1Address := addressOf("acc1")
    58  	acc1, err := cache.GetAccount(acc1Address)
    59  	require.NoError(t, err)
    60  	assert.Equal(t, uint64(0), acc1.Balance)
    61  
    62  	acc1Exp := readBackend.Accounts[acc1Address]
    63  	assert.True(t, acc1Exp.Equal(acc1), "accounts should be equal")
    64  	acc8, err := cache.GetAccount(addressOf("acc8"))
    65  	require.NoError(t, err)
    66  	assert.Nil(t, acc8)
    67  }
    68  
    69  func TestStateCache_UpdateAccount(t *testing.T) {
    70  	// Build backend states for read and write
    71  	backend := NewCache(NewMemoryState())
    72  	cache := NewCache(backend)
    73  	// Create acccount
    74  	accNew := acm.NewAccountFromSecret("accNew")
    75  	balance := uint64(0xff)
    76  	accNew.Balance = balance
    77  	err := cache.UpdateAccount(accNew)
    78  	require.NoError(t, err)
    79  
    80  	// Check cache
    81  	accNewOut, err := cache.GetAccount(accNew.Address)
    82  	require.NoError(t, err)
    83  	assert.Equal(t, balance, accNewOut.Balance)
    84  
    85  	// Check not stored in backend
    86  	accNewOut, err = backend.GetAccount(accNew.Address)
    87  	require.NoError(t, err)
    88  	assert.Nil(t, accNewOut)
    89  
    90  	// Check syncs to backend
    91  	err = cache.Sync(backend)
    92  	require.NoError(t, err)
    93  	accNewOut, err = backend.GetAccount(accNew.Address)
    94  	require.NoError(t, err)
    95  	assert.Equal(t, balance, accNewOut.Balance)
    96  
    97  	// Alter in cache
    98  	newBalance := uint64(0xff00aa)
    99  	accNew.Balance = newBalance
   100  	err = cache.UpdateAccount(accNew)
   101  	require.NoError(t, err)
   102  
   103  	// Check cache
   104  	accNewOut, err = cache.GetAccount(accNew.Address)
   105  	require.NoError(t, err)
   106  	assert.Equal(t, newBalance, accNewOut.Balance)
   107  
   108  	// Check backend unchanged
   109  	accNewOut, err = backend.GetAccount(accNew.Address)
   110  	require.NoError(t, err)
   111  	assert.Equal(t, balance, accNewOut.Balance)
   112  
   113  	require.Equal(t, accNewOut == accNew, false)
   114  }
   115  
   116  func TestStateCache_RemoveAccount(t *testing.T) {
   117  	// Build backend states for read and write
   118  	backend := NewCache(NewMemoryState())
   119  	cache := NewCache(backend)
   120  
   121  	//Create new account
   122  	newAcc := acm.NewAccountFromSecret("newAcc")
   123  	err := cache.UpdateAccount(newAcc)
   124  	require.NoError(t, err)
   125  
   126  	//Sync account to backend
   127  	err = cache.Sync(backend)
   128  	require.NoError(t, err)
   129  
   130  	//Check for account in cache
   131  	newAccOut, err := cache.GetAccount(newAcc.Address)
   132  	require.NoError(t, err)
   133  	require.NotNil(t, newAccOut)
   134  
   135  	//Check for account in backend
   136  	newAccOut, err = backend.GetAccount(newAcc.Address)
   137  	require.NoError(t, err)
   138  	require.NotNil(t, newAccOut)
   139  
   140  	//Remove account from cache and backend
   141  	err = cache.RemoveAccount(newAcc.Address)
   142  	require.NoError(t, err)
   143  	err = cache.Sync(backend)
   144  	require.NoError(t, err)
   145  
   146  	//Check that account is removed from cache
   147  	newAccOut, err = cache.GetAccount(newAcc.Address)
   148  	require.NoError(t, err)
   149  	require.Nil(t, newAccOut)
   150  
   151  	//Check that account is removed from backend
   152  	newAccOut, err = backend.GetAccount(newAcc.Address)
   153  	require.NoError(t, err)
   154  	require.Nil(t, newAccOut)
   155  }
   156  
   157  func TestStateCache_GetStorage(t *testing.T) {
   158  	// Build backend states for read and write
   159  	readBackend := testAccounts()
   160  	writeBackend := NewCache(NewMemoryState())
   161  	cache := NewCache(readBackend)
   162  
   163  	//Create account
   164  	acc := readBackend.Accounts[addressOf("acc1")]
   165  
   166  	//Get storage from cache
   167  	accStorage, err := cache.GetStorage(acc.Address, word("I AM A KEY"))
   168  	require.NoError(t, err)
   169  	cache.UpdateAccount(acc)
   170  
   171  	//Check for correct cache storage value
   172  	assert.Equal(t, "NO YOU ARE A KEY", string(accStorage))
   173  
   174  	//Sync account to backend
   175  	err = cache.Sync(writeBackend)
   176  	require.NoError(t, err)
   177  
   178  	//Get storage from backend
   179  	accStorage, err = writeBackend.GetStorage(acc.Address, word("I AM A KEY"))
   180  	assert.NoError(t, err)
   181  	require.NotNil(t, accStorage)
   182  
   183  	//Check for correct backend storage value
   184  	assert.Equal(t, "NO YOU ARE A KEY", string(accStorage))
   185  }
   186  
   187  func TestStateCache_SetStorage(t *testing.T) {
   188  	// Build backend states for read and write
   189  	backend := NewCache(NewMemoryState())
   190  	cache := NewCache(backend)
   191  
   192  	//Create new account and set its storage in cache
   193  	newAcc := acm.NewAccountFromSecret("newAcc")
   194  	err := cache.UpdateAccount(newAcc)
   195  	require.NoError(t, err)
   196  	err = cache.SetStorage(newAcc.Address, word("What?"), []byte("Huh?"))
   197  	require.NoError(t, err)
   198  
   199  	//Check for correct cache storage value
   200  	newAccStorage, err := cache.GetStorage(newAcc.Address, word("What?"))
   201  	require.NoError(t, err)
   202  	assert.Equal(t, "Huh?", string(newAccStorage))
   203  
   204  	//Sync account to backend
   205  	err = cache.Sync(backend)
   206  	require.NoError(t, err)
   207  
   208  	//Check for correct backend storage value
   209  	newAccStorage, err = backend.GetStorage(newAcc.Address, word("What?"))
   210  	require.NoError(t, err)
   211  	assert.Equal(t, "Huh?", string(newAccStorage))
   212  
   213  	noone := acm.NewAccountFromSecret("noone at all")
   214  	err = cache.SetStorage(noone.Address, binary.Word256{3, 4, 5}, []byte{102, 103, 104})
   215  	require.Error(t, err, "should not be able to write to non-existent account")
   216  
   217  	err = cache.UpdateAccount(noone)
   218  	require.NoError(t, err)
   219  	err = cache.SetStorage(noone.Address, binary.Word256{3, 4, 5}, []byte{102, 103, 104})
   220  	require.NoError(t, err, "should be able to update account after creating it")
   221  }
   222  
   223  func TestStateCache_Sync(t *testing.T) {
   224  	// Build backend states for read and write
   225  	backend := NewCache(NewMemoryState())
   226  	cache := NewCache(backend)
   227  
   228  	// Create new account
   229  	// Create account
   230  	newAcc := acm.NewAccountFromSecret("newAcc")
   231  	err := cache.UpdateAccount(newAcc)
   232  	require.NoError(t, err)
   233  
   234  	// Set balance for account
   235  	balance := uint64(24)
   236  	newAcc.Balance = balance
   237  
   238  	// Set storage for account
   239  	err = cache.SetStorage(newAcc.Address, word("God save"), []byte("the queen!"))
   240  	require.NoError(t, err)
   241  
   242  	//Update cache with account changes
   243  	err = cache.UpdateAccount(newAcc)
   244  	require.NoError(t, err)
   245  
   246  	//Confirm changes to account balance in cache
   247  	newAccOut, err := cache.GetAccount(newAcc.Address)
   248  	require.NoError(t, err)
   249  	assert.Equal(t, balance, newAccOut.Balance)
   250  
   251  	//Confirm changes to account storage in cache
   252  	newAccStorage, err := cache.GetStorage(newAcc.Address, word("God save"))
   253  	require.NoError(t, err)
   254  	assert.Equal(t, "the queen!", string(newAccStorage))
   255  
   256  	//Sync account to backend
   257  	err = cache.Sync(backend)
   258  	require.NoError(t, err)
   259  
   260  	//Confirm changes to account balance synced correctly to backend
   261  	newAccOut, err = backend.GetAccount(newAcc.Address)
   262  	require.NoError(t, err)
   263  	assert.Equal(t, balance, newAccOut.Balance)
   264  
   265  	//Confirm changes to account storage synced correctly to backend
   266  	newAccStorage, err = cache.GetStorage(newAcc.Address, word("God save"))
   267  	require.NoError(t, err)
   268  	assert.Equal(t, "the queen!", string(newAccStorage))
   269  
   270  	//Remove account from cache
   271  	err = cache.RemoveAccount(newAcc.Address)
   272  	require.NoError(t, err)
   273  
   274  	//Sync account removal to backend
   275  	err = cache.Sync(backend)
   276  	require.NoError(t, err)
   277  
   278  	//Check that account removal synced correctly to backend
   279  	newAccOut, err = backend.GetAccount(newAcc.Address)
   280  	require.NoError(t, err)
   281  	require.Nil(t, newAccOut)
   282  }
   283  
   284  func TestStateCache_get(t *testing.T) {
   285  	backend := NewCache(NewMemoryState())
   286  	cache := NewCache(backend)
   287  
   288  	//Create new account
   289  	newAcc := acm.NewAccountFromSecret("newAcc")
   290  
   291  	//Add new account to cache
   292  	err := cache.UpdateAccount(newAcc)
   293  	require.NoError(t, err)
   294  
   295  	//Check that get returns an account from cache
   296  	newAccOut, err := cache.GetAccount(newAcc.Address)
   297  	require.NoError(t, err)
   298  	require.NotNil(t, newAccOut)
   299  
   300  	//Sync account to backend
   301  	err = cache.Sync(backend)
   302  	require.NoError(t, err)
   303  
   304  	//Check that get returns an account from backend
   305  	newAccOut, err = backend.GetAccount(newAcc.Address)
   306  	require.NoError(t, err)
   307  	require.NotNil(t, newAccOut)
   308  }
   309  
   310  func testAccounts() *MemoryState {
   311  	acc1 := acm.NewAccountFromSecret("acc1")
   312  	acc1.Permissions.Base.Perms = permission.AddRole | permission.Send
   313  	acc1.Permissions.Base.SetBit = acc1.Permissions.Base.Perms
   314  
   315  	acc2 := acm.NewAccountFromSecret("acc2")
   316  	acc2.Permissions.Base.Perms = permission.AddRole | permission.Send
   317  	acc2.Permissions.Base.SetBit = acc1.Permissions.Base.Perms
   318  	acc2.EVMCode, _ = acm.NewBytecode(asm.PUSH1, 0x20)
   319  
   320  	cache := combine(
   321  		account(acc1, "I AM A KEY", "NO YOU ARE A KEY"),
   322  		account(acc2, "ducks", "have lucks",
   323  			"chickens", "just cluck"),
   324  	)
   325  	return cache
   326  }
   327  
   328  func addressOf(secret string) crypto.Address {
   329  	return acm.NewAccountFromSecret(secret).Address
   330  }
   331  
   332  func account(acc *acm.Account, keyvals ...string) *MemoryState {
   333  	ts := NewMemoryState()
   334  	ts.Accounts[acc.Address] = acc
   335  	ts.Storage[acc.Address] = make(map[binary.Word256][]byte)
   336  	for i := 0; i < len(keyvals); i += 2 {
   337  		ts.Storage[acc.Address][word(keyvals[i])] = []byte(keyvals[i+1])
   338  	}
   339  	return ts
   340  }
   341  
   342  func combine(states ...*MemoryState) *MemoryState {
   343  	ts := NewMemoryState()
   344  	for _, state := range states {
   345  		for _, acc := range state.Accounts {
   346  			ts.Accounts[acc.Address] = acc
   347  			ts.Storage[acc.Address] = state.Storage[acc.Address]
   348  		}
   349  	}
   350  	return ts
   351  }
   352  
   353  func word(str string) binary.Word256 {
   354  	return binary.LeftPadWord256([]byte(str))
   355  }