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 }