Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rework to inherit QueryAccount (429-syscall-account-cache)
  • Loading branch information
vakond committed Dec 21, 2021
commit 0cf4732a3f21589335dbc4406419c562ec983199
170 changes: 92 additions & 78 deletions proxy/testing/test_query_account_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,58 +40,51 @@

// Takes a Solana address, treats it as an address of an account.
// Puts the metadata and a chunk of data into the cache.
function cache(uint256 solana_address, uint64 offset, uint64 len) public {
function cache(uint256 solana_address, uint64 offset, uint64 len) public returns (bool) {
(bool success, bytes memory _dummy) = precompiled.staticcall(abi.encodeWithSignature("cache(uint256,uint64,uint64)", solana_address, offset, len));
require(success, "QueryAccount.cache failed");
return success;
}

// Takes a Solana address, treats it as an address of an account.
// Returns the account's owner Solana address (32 bytes).
function owner(uint256 solana_address) public view returns (uint256) {
function owner(uint256 solana_address) public view returns (bool, uint256) {
(bool success, bytes memory result) = precompiled.staticcall(abi.encodeWithSignature("owner(uint256)", solana_address));
require(success, "QueryAccount.owner failed");
return to_uint256(result);
return (success, to_uint256(result));
}

// Takes a Solana address, treats it as an address of an account.
// Returns the length of the account's data (8 bytes).
function length(uint256 solana_address) public view returns (uint256) {
function length(uint256 solana_address) public view returns (bool, uint256) {
(bool success, bytes memory result) = precompiled.staticcall(abi.encodeWithSignature("length(uint256)", solana_address));
require(success, "QueryAccount.length failed");
return to_uint256(result);
return (success, to_uint256(result));
}

// Takes a Solana address, treats it as an address of an account.
// Returns the funds in lamports of the account.
function lamports(uint256 solana_address) public view returns (uint256) {
function lamports(uint256 solana_address) public view returns (bool, uint256) {
(bool success, bytes memory result) = precompiled.staticcall(abi.encodeWithSignature("lamports(uint256)", solana_address));
require(success, "QueryAccount.lamports failed");
return to_uint256(result);
return (success, to_uint256(result));
}

// Takes a Solana address, treats it as an address of an account.
// Returns the executable flag of the account.
function executable(uint256 solana_address) public view returns (bool) {
function executable(uint256 solana_address) public view returns (bool, bool) {
(bool success, bytes memory result) = precompiled.staticcall(abi.encodeWithSignature("executable(uint256)", solana_address));
require(success, "QueryAccount.executable failed");
return to_bool(result);
return (success, to_bool(result));
}

// Takes a Solana address, treats it as an address of an account.
// Returns the rent epoch of the account.
function rent_epoch(uint256 solana_address) public view returns (uint256) {
function rent_epoch(uint256 solana_address) public view returns (bool, uint256) {
(bool success, bytes memory result) = precompiled.staticcall(abi.encodeWithSignature("rent_epoch(uint256)", solana_address));
require(success, "QueryAccount.rent_epoch failed");
return to_uint256(result);
return (success, to_uint256(result));
}

// Takes a Solana address, treats it as an address of an account,
// also takes an offset and length of the account's data.
// Returns a chunk of the data (length bytes).
function data(uint256 solana_address, uint64 offset, uint64 len) public view returns (bytes memory) {
(bool success, bytes memory result) = precompiled.staticcall(abi.encodeWithSignature("data(uint256,uint64,uint64)", solana_address, offset, len));
require(success, "QueryAccount.data failed");
return result;
function data(uint256 solana_address, uint64 offset, uint64 len) public view returns (bool, bytes memory) {
return precompiled.staticcall(abi.encodeWithSignature("data(uint256,uint64,uint64)", solana_address, offset, len));
}

function to_uint256(bytes memory bb) private pure returns (uint256 result) {
Expand All @@ -107,109 +100,125 @@
}
}

contract TestQueryAccount {
QueryAccount query;

contract TestQueryAccount is QueryAccount {
uint256 constant solana_account = 110178555362476360822489549210862241441608066866019832842197691544474470948129;
uint256 constant missing_account = 90000;

constructor() {
query = new QueryAccount();
}

function test_cache() public returns (bool) {
bool ok = false;
// Put
bool ok = super.cache(solana_account, 0, 64);
if (!ok) { return false; }

// Replace
ok = super.cache(solana_account, 0, 82);
if (!ok) { return false; }

// Normal
try query.cache(solana_account, 0, 64) { ok = true; } catch { ok = false; }
if (!ok) { return ok; }
// Zero length
ok = super.cache(solana_account, 0, 0);
if (ok) { return false; }

// Length too long
try query.cache(solana_account, 0, 200) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
ok = super.cache(solana_account, 0, 200);
if (ok) { return false; }

// Offset too big
try query.cache(solana_account, 200, 16) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
ok = super.cache(solana_account, 200, 16);
if (ok) { return false; }

// Nonexistent account
try query.cache(missing_account, 0, 1) { ok = false; } catch { ok = true; /* expected exception */ }
ok = super.cache(missing_account, 0, 1);
if (ok) { return false; }

return ok;
return true;
}

function test_noncached() public returns (bool) {
bool ok = false;
bool ok;
uint256 _u;
bool _b;
bytes memory _m;

try query.owner(solana_account) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
(ok, _u) = super.owner(solana_account);
if (ok) { return false; }

try query.length(solana_account) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
(ok, _u) = super.length(solana_account);
if (ok) { return false; }

try query.lamports(solana_account) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
(ok, _u) = super.lamports(solana_account);
if (ok) { return false; }

try query.executable(solana_account) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
(ok, _b) = super.executable(solana_account);
if (ok) { return false; }

try query.rent_epoch(solana_account) { ok = false; } catch { ok = true; /* expected exception */ }
if (!ok) { return ok; }
(ok, _u) = super.rent_epoch(solana_account);
if (ok) { return false; }

try query.data(solana_account, 0, 1) { ok = false; } catch { ok = true; /* expected exception */ }
(ok, _m) = super.data(solana_account, 0, 1);
if (ok) { return false; }

return ok;
return true;
}

function test_metadata_ok() public returns (bool) {
query.cache(solana_account, 0, 64);
bool ok = super.cache(solana_account, 0, 64);
if (!ok) { return false; }

uint256 golden_owner = 3106054211088883198575105191760876350940303353676611666299516346430146937001;
uint256 golden_len = 82;
uint256 golden_lamp = 1461600;
bool golden_exec = false;
uint256 golden_repoch = 0;

uint256 ownr = query.owner(solana_account);
if (ownr != golden_owner) {
uint256 ownr;
(ok, ownr) = super.owner(solana_account);
if (!ok || ownr != golden_owner) {
return false;
}

uint len = query.length(solana_account);
if (len != golden_len) {
uint len;
(ok, len) = super.length(solana_account);
if (!ok || len != golden_len) {
return false;
}

uint256 lamp = query.lamports(solana_account);
if (lamp != golden_lamp) {
uint256 lamp;
(ok, lamp) = super.lamports(solana_account);
if (!ok || lamp != golden_lamp) {
return false;
}

bool exec = query.executable(solana_account);
if (exec != golden_exec) {
bool exec;
(ok, exec) = super.executable(solana_account);
if (!ok || exec != golden_exec) {
return false;
}

uint256 repoch = query.rent_epoch(solana_account);
if (repoch != golden_repoch) {
uint256 repoch;
(ok, repoch) = super.rent_epoch(solana_account);
if (!ok || repoch != golden_repoch) {
return false;
}

return true;
}

function test_data_ok() public returns (bool) {
query.cache(solana_account, 0, 64);
bool ok = super.cache(solana_account, 0, 64);
if (!ok) { return false; }

byte b0 = 0x71;
byte b1 = 0x33;
byte b2 = 0xc6;
byte b3 = 0x12;

// Test getting subset of data
// Get subset of data
uint64 offset = 20;
uint64 len = 4;
bytes memory result = query.data(solana_account, offset, len);
bytes memory result;
(ok, result) = super.data(solana_account, offset, len);
if (!ok) {
return false;
}
if (result.length != 4) {
return false;
}
Expand All @@ -225,37 +234,42 @@
if (result[3] != b3) {
return false;
}
// Test getting full data

// Get full data
offset = 0;
len = 64;
result = query.data(solana_account, offset, len);
if (result.length != 64) {
(ok, result) = super.data(solana_account, offset, len);
if (!ok || result.length != 64) {
return false;
}

return true;
}

function test_data_too_big_offset() public returns (bool) {
query.cache(solana_account, 0, 82);
bool ok = super.cache(solana_account, 0, 82);
if (!ok) { return false; }

uint64 offset = 200; // data len is 82
uint64 len = 1;
try query.data(solana_account, offset, len) { } catch {
return true; // expected exception
}
return false;
bytes memory _m;
(ok, _m) = super.data(solana_account, offset, len);
if (ok) { return false; }

return true;
}

function test_data_too_big_length() public returns (bool) {
query.cache(solana_account, 0, 82);
bool ok = super.cache(solana_account, 0, 82);
if (!ok) { return false; }

uint64 offset = 0;
uint64 len = 200; // data len is 82
try query.data(solana_account, offset, len) { } catch {
return true; // expected exception
}
return false;
bytes memory _m;
(ok, _m) = super.data(solana_account, offset, len);
if (ok) { return false; }

return true;
}
}
'''
Expand Down