Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Contract updates (WIP) #11514

Open
wants to merge 53 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b2d2392
feat: Add update contract fn and test contracts
sirasistant Jan 20, 2025
867fc56
fix
sirasistant Jan 20, 2025
4fd2c2a
Merge branch 'master' into arv/set_code
sirasistant Jan 21, 2025
4bda8c7
kernel changes
sirasistant Jan 23, 2025
c3f004b
fixes
sirasistant Jan 23, 2025
953d483
fix
sirasistant Jan 23, 2025
1beef36
wip
sirasistant Jan 24, 2025
f074daa
changes
sirasistant Jan 24, 2025
5efaeed
Merge branch 'master' into arv/set_code
sirasistant Jan 24, 2025
8de83e3
fix
sirasistant Jan 27, 2025
a6f2e8a
Merge branch 'master' into arv/set_code
sirasistant Jan 27, 2025
8ba771c
bug repro
sirasistant Jan 27, 2025
eae28a0
bug report
sirasistant Jan 27, 2025
d1ea8dc
added noop to bypass bug
sirasistant Jan 27, 2025
038f508
Merge branch 'master' into arv/set_code
sirasistant Jan 27, 2025
a4dfbdc
Private function updates
sirasistant Jan 28, 2025
2dfc0cc
towards public updates
sirasistant Jan 28, 2025
93e5a61
update memory store
sirasistant Jan 29, 2025
1ed42d2
fix archiving
sirasistant Jan 29, 2025
cbd863d
add originalClassId
sirasistant Jan 29, 2025
2570da0
Merge branch 'master' into arv/set_code
sirasistant Jan 29, 2025
ddf4c27
fix
sirasistant Jan 29, 2025
cbc42cb
fix
sirasistant Jan 30, 2025
4e4ace7
fixes after merge
sirasistant Jan 30, 2025
8f30be9
moar fixes
sirasistant Jan 30, 2025
3978506
pass hints to the avm
sirasistant Jan 30, 2025
5ef9f10
Merge branch 'master' into arv/set_code
sirasistant Jan 30, 2025
d73ccd9
fixes
sirasistant Jan 30, 2025
d81a250
add validation in vm1
sirasistant Jan 31, 2025
14d9adc
Merge branch 'master' into arv/set_code
sirasistant Jan 31, 2025
1282abf
Merge branch 'master' into arv/set_code
sirasistant Jan 31, 2025
53a3caf
remove extraneous file
sirasistant Jan 31, 2025
a557ad9
use shared constants
sirasistant Jan 31, 2025
406c15d
refactor value and delay change
sirasistant Jan 31, 2025
4db32ec
Merge branch 'master' into arv/set_code
sirasistant Jan 31, 2025
4bfa0c6
Merge branch 'master' into arv/set_code
sirasistant Jan 31, 2025
bee6541
Merge branch 'master' into arv/set_code
sirasistant Feb 3, 2025
6383365
add current class id check
sirasistant Feb 3, 2025
f3713db
Merge branch 'master' into arv/set_code
sirasistant Feb 3, 2025
0f0da77
fix some tests
sirasistant Feb 3, 2025
1b384c8
fix moar tests
sirasistant Feb 4, 2025
e1e99c4
Merge branch 'master' into arv/set_code
sirasistant Feb 4, 2025
fd5e009
fix
sirasistant Feb 4, 2025
65dae9d
fixes
sirasistant Feb 4, 2025
208d1ff
Merge branch 'master' into arv/set_code
sirasistant Feb 4, 2025
93b8a05
fix
sirasistant Feb 4, 2025
a7cd684
fix vm2 serialization
sirasistant Feb 4, 2025
6b7036f
final fixes
sirasistant Feb 4, 2025
4a1211c
regen test data
sirasistant Feb 5, 2025
416c424
fix tests
sirasistant Feb 5, 2025
dacbe94
moar fixes
sirasistant Feb 5, 2025
8a7ba14
Merge branch 'master' into arv/set_code
sirasistant Feb 5, 2025
07e2b9f
update tomls
sirasistant Feb 5, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@ class AvmExecutionTests : public ::testing::Test {
auto tagging_key = grumpkin::g1::affine_one;
PublicKeysHint public_keys{ nullifier_key, incoming_viewing_key, outgoing_viewing_key, tagging_key };
ContractInstanceHint contract_instance = {
FF::one() /* temp address */, true /* exists */, FF(2) /* salt */, FF(3) /* deployer_addr */, class_id,
FF::one() /* temp address */, true /* exists */, FF(2) /* salt */, FF(3) /* deployer_addr */, class_id, class_id,
FF(8) /* initialisation_hash */, public_keys,
/*membership_hint=*/ { .low_leaf_preimage = { .nullifier = 0, .next_nullifier = 0, .next_index = 0, }, .low_leaf_index = 0, .low_leaf_sibling_path = {} },
/* update_hint*/ { .leaf_preimage = { .slot = 0, .value = 0, .next_index = 0, .next_slot = 0, }, .leaf_index = 0, .sibling_path = {} },
/* update_preimage */ {},
};
FF address = AvmBytecodeTraceBuilder::compute_address_from_instance(contract_instance);
contract_instance.address = address;
Expand Down Expand Up @@ -2293,10 +2295,13 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcode)
.exists = true,
.salt = 2,
.deployer_addr = 42,
.contract_class_id = 66,
.current_contract_class_id = 66,
.original_contract_class_id = 66,
.initialisation_hash = 99,
.public_keys = public_keys_hints,
.membership_hint = { .low_leaf_preimage = { .nullifier = 0, .next_nullifier = 0, .next_index = 0, }, .low_leaf_index = 0, .low_leaf_sibling_path = {} },
.initialization_membership_hint = { .low_leaf_preimage = { .nullifier = 0, .next_nullifier = 0, .next_index = 0, }, .low_leaf_index = 0, .low_leaf_sibling_path = {} },
.update_membership_hint = { .leaf_preimage = { .slot = 0, .value = 0, .next_index = 0, .next_slot = 0, }, .leaf_index = 0, .sibling_path = {} },
.update_preimage = {}
};
auto execution_hints = ExecutionHints().with_contract_instance_hints({ { address, instance } });

Expand Down Expand Up @@ -2341,7 +2346,7 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcode)
std::vector<FF> const calldata{};
// alternating member value, exists bool
std::vector<FF> const expected_returndata = {
instance.deployer_addr, 1, instance.contract_class_id, 1, instance.initialisation_hash, 1,
instance.deployer_addr, 1, instance.current_contract_class_id, 1, instance.initialisation_hash, 1,
};

std::vector<FF> returndata{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ FF AvmBytecodeTraceBuilder::compute_address_from_instance(const ContractInstance
contract_instance.initialisation_hash,
contract_instance.deployer_addr });
FF partial_address = poseidon2::hash(
{ GENERATOR_INDEX__PARTIAL_ADDRESS, contract_instance.contract_class_id, salted_initialization_hash });
{ GENERATOR_INDEX__PARTIAL_ADDRESS, contract_instance.original_contract_class_id, salted_initialization_hash });

std::vector<FF> public_keys_hash_fields = contract_instance.public_keys.to_fields();
std::vector<FF> public_key_hash_vec{ GENERATOR_INDEX__PUBLIC_KEYS_HASH };
Expand Down Expand Up @@ -144,7 +144,7 @@ void AvmBytecodeTraceBuilder::build_bytecode_hash_columns()
contract_bytecode.contract_class_id_preimage.private_fn_root,
running_hash);
// Assert that the computed class id is the same as what we received as the hint
ASSERT(last_entry.class_id == contract_bytecode.contract_instance.contract_class_id);
ASSERT(last_entry.class_id == contract_bytecode.contract_instance.current_contract_class_id);

last_entry.contract_address = compute_address_from_instance(contract_bytecode.contract_instance);
// Assert that the computed contract address is the same as what we received as the hint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,13 @@ struct ContractInstanceHint {
bool exists; // Useful for membership checks
FF salt{};
FF deployer_addr{};
FF contract_class_id{};
FF current_contract_class_id{};
FF original_contract_class_id{};
FF initialisation_hash{};
PublicKeysHint public_keys;
NullifierReadTreeHint membership_hint;
NullifierReadTreeHint initialization_membership_hint;
PublicDataReadTreeHint update_membership_hint;
std::vector<FF> update_preimage;
};

inline void read(uint8_t const*& it, PublicKeysHint& hint)
Expand All @@ -187,10 +190,13 @@ inline void read(uint8_t const*& it, ContractInstanceHint& hint)
read(it, hint.exists);
read(it, hint.salt);
read(it, hint.deployer_addr);
read(it, hint.contract_class_id);
read(it, hint.current_contract_class_id);
read(it, hint.original_contract_class_id);
read(it, hint.initialisation_hash);
read(it, hint.public_keys);
read(it, hint.membership_hint);
read(it, hint.initialization_membership_hint);
read(it, hint.update_membership_hint);
read(it, hint.update_preimage);
}

struct AvmContractBytecode {
Expand Down
70 changes: 60 additions & 10 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,67 @@ std::vector<uint8_t> AvmTraceBuilder::get_bytecode_from_hints(const FF contract_
// TODO: still need to make sure that the contract address does correspond to this class id
const AvmContractBytecode bytecode_hint =
*std::ranges::find_if(execution_hints.all_contract_bytecode, [contract_class_id](const auto& contract) {
return contract.contract_instance.contract_class_id == contract_class_id;
return contract.contract_instance.current_contract_class_id == contract_class_id;
});
return bytecode_hint.bytecode;
}

void AvmTraceBuilder::validate_contract_instance_current_class_id(uint32_t clk, const ContractInstanceHint& instance)
{
if (is_canonical(instance.address)) {
return;
}
// First validate the update_preimage against the public data tree
PublicDataReadTreeHint read_hint = instance.update_membership_hint;

const FF shared_mutable_slot = Poseidon2::hash({ UPDATED_CLASS_IDS_SLOT, instance.address });
const FF hash_slot = Poseidon2::hash({ SHARED_MUTABLE_HASH_SEPARATOR, shared_mutable_slot });
const FF hash_leaf_slot =
AvmMerkleTreeTraceBuilder::unconstrained_compute_public_tree_leaf_slot(DEPLOYER_CONTRACT_ADDRESS, hash_slot);
bool exists = read_hint.leaf_preimage.slot == hash_leaf_slot;

bool is_member = merkle_tree_trace_builder.perform_storage_read(
clk, read_hint.leaf_preimage, read_hint.leaf_index, read_hint.sibling_path);
// membership check must always pass
ASSERT(is_member);

if (exists) {
const FF reproduced_hash = Poseidon2::hash(instance.update_preimage);
ASSERT(reproduced_hash == read_hint.leaf_preimage.value);
} else {
AvmMerkleTreeTraceBuilder::assert_public_data_non_membership_check(read_hint.leaf_preimage, hash_leaf_slot);
// ensure instance.update_preimage is all zeroes
ASSERT(std::all_of(
instance.update_preimage.begin(), instance.update_preimage.end(), [](const auto& x) { return x == 0; }));
}

// update_preimage is validated, now validate the contract class id
FF expected_current_class_id;
const FF prev_value = instance.update_preimage[0];
const FF next_value = instance.update_preimage[1];
const uint32_t block_of_change = static_cast<uint32_t>(instance.update_preimage[2]);

// Fourth item is related to update delays which we don't care.
if (static_cast<uint32_t>(public_inputs.global_variables.block_number) < block_of_change) {
// original class id was validated against the address
expected_current_class_id = prev_value == 0 ? instance.original_contract_class_id : prev_value;
} else {
expected_current_class_id = next_value == 0 ? instance.original_contract_class_id : next_value;
}
ASSERT(expected_current_class_id == instance.current_contract_class_id);
}

std::vector<uint8_t> AvmTraceBuilder::get_bytecode(const FF contract_address, bool check_membership)
{
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;

ASSERT(execution_hints.contract_instance_hints.contains(contract_address));
const ContractInstanceHint instance_hint = execution_hints.contract_instance_hints.at(contract_address);
const FF contract_class_id = instance_hint.contract_class_id;
const FF contract_class_id = instance_hint.current_contract_class_id;

bool exists = true;
if (check_membership && !is_canonical(contract_address)) {
if (bytecode_membership_cache.find(contract_address) != bytecode_membership_cache.end()) {
if (contract_instance_membership_cache.find(contract_address) != contract_instance_membership_cache.end()) {
// If we have already seen the contract address, we can skip the membership check and used the cached
// membership proof
vinfo("Found bytecode for contract address in cache: ", contract_address);
Expand All @@ -195,7 +240,7 @@ std::vector<uint8_t> AvmTraceBuilder::get_bytecode(const FF contract_address, bo
const auto contract_address_nullifier = AvmMerkleTreeTraceBuilder::unconstrained_silo_nullifier(
DEPLOYER_CONTRACT_ADDRESS, /*nullifier=*/contract_address);
// nullifier read hint for the contract address
NullifierReadTreeHint nullifier_read_hint = instance_hint.membership_hint;
NullifierReadTreeHint nullifier_read_hint = instance_hint.initialization_membership_hint;

// If the hinted preimage matches the contract address nullifier, the membership check will prove its existence,
// otherwise the membership check will prove that a low-leaf exists that skips the contract address nullifier.
Expand All @@ -212,7 +257,7 @@ std::vector<uint8_t> AvmTraceBuilder::get_bytecode(const FF contract_address, bo
// This was a membership proof!
// Assert that the hint's exists flag matches. The flag isn't really necessary...
ASSERT(instance_hint.exists);
bytecode_membership_cache.insert(contract_address);
contract_instance_membership_cache.insert(contract_address);

// The cache contains all the unique contract class ids we have seen so far
// If this bytecode retrievals have reached the number of unique contract class IDs, can't make
Expand All @@ -223,7 +268,8 @@ std::vector<uint8_t> AvmTraceBuilder::get_bytecode(const FF contract_address, bo
MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS);
throw std::runtime_error("Limit reached for contract calls to unique class id.");
}
contract_class_id_cache.insert(instance_hint.contract_class_id);
contract_class_id_cache.insert(instance_hint.current_contract_class_id);
validate_contract_instance_current_class_id(clk, instance_hint);
return get_bytecode_from_hints(contract_class_id);
} else {
// This was a non-membership proof!
Expand Down Expand Up @@ -3507,12 +3553,13 @@ AvmError AvmTraceBuilder::op_get_contract_instance(
// Read the contract instance hint
ContractInstanceHint instance = execution_hints.contract_instance_hints.at(contract_address);

if (is_canonical(contract_address)) {
// skip membership check for canonical contracts
if (is_canonical(contract_address) ||
(contract_instance_membership_cache.find(contract_address) != contract_instance_membership_cache.end())) {
// skip membership check for canonical contracts and contracts already verified
exists = true;
} else {
// nullifier read hint for the contract address
NullifierReadTreeHint nullifier_read_hint = instance.membership_hint;
NullifierReadTreeHint nullifier_read_hint = instance.initialization_membership_hint;

// If the hinted preimage matches the contract address nullifier, the membership check will prove its
// existence, otherwise the membership check will prove that a low-leaf exists that skips the contract
Expand All @@ -3539,6 +3586,9 @@ AvmError AvmTraceBuilder::op_get_contract_instance(
(nullifier_read_hint.low_leaf_preimage.next_nullifier == FF::zero() ||
contract_address_nullifier > nullifier_read_hint.low_leaf_preimage.next_nullifier));
}
validate_contract_instance_current_class_id(clk, instance);

contract_instance_membership_cache.insert(contract_address);
}

if (exists) {
Expand All @@ -3547,7 +3597,7 @@ AvmError AvmTraceBuilder::op_get_contract_instance(
member_value = instance.deployer_addr;
break;
case ContractInstanceMember::CLASS_ID:
member_value = instance.contract_class_id;
member_value = instance.current_contract_class_id;
break;
case ContractInstanceMember::INIT_HASH:
member_value = instance.initialisation_hash;
Expand Down
4 changes: 3 additions & 1 deletion barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,11 @@ class AvmTraceBuilder {
void checkpoint_non_revertible_state();
void rollback_to_non_revertible_checkpoint();
std::vector<uint8_t> get_bytecode(const FF contract_address, bool check_membership = false);
void validate_contract_instance_current_class_id(uint32_t clk, const ContractInstanceHint& instance);

// Used to track the unique class ids, could also be used to cache membership checks of class ids
std::unordered_set<FF> contract_class_id_cache;
std::unordered_set<FF> bytecode_membership_cache;
std::unordered_set<FF> contract_instance_membership_cache;
void insert_private_state(const std::vector<FF>& siloed_nullifiers, const std::vector<FF>& unique_note_hashes);
void insert_private_revertible_state(const std::vector<FF>& siloed_nullifiers,
const std::vector<FF>& siloed_note_hashes);
Expand Down
4 changes: 4 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
#define FEE_JUICE_ADDRESS 5
#define ROUTER_ADDRESS 6
#define FEE_JUICE_BALANCES_SLOT 1
#define UPDATED_CLASS_IDS_SLOT 1
#define SHARED_MUTABLE_VALUE_CHANGE_SEPARATOR 0
#define SHARED_MUTABLE_DELAY_CHANGE_SEPARATOR 1
#define SHARED_MUTABLE_HASH_SEPARATOR 2
#define AZTEC_ADDRESS_LENGTH 1
#define GAS_FEES_LENGTH 2
#define GAS_LENGTH 2
Expand Down
12 changes: 10 additions & 2 deletions barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,22 @@ struct ContractInstanceHint {
bool exists;
FF salt;
AztecAddress deployer;
ContractClassId contractClassId;
ContractClassId currentContractClassId;
ContractClassId originalContractClassId;
FF initializationHash;
PublicKeysHint publicKeys;
// TODO: missing membership hints.

bool operator==(const ContractInstanceHint& other) const = default;

MSGPACK_FIELDS(address, exists, salt, deployer, contractClassId, initializationHash, publicKeys);
MSGPACK_FIELDS(address,
exists,
salt,
deployer,
currentContractClassId,
originalContractClassId,
initializationHash,
publicKeys);
};

struct ContractClassHint {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ TEST(AvmInputsTest, Deserialization)
.exists = true,
.salt = FF(0xdeadbeef),
.deployer = AztecAddress(0x000010),
.contractClassId = ContractClassId(0x41181337),
.currentContractClassId = ContractClassId(0x41181337),
.originalContractClassId = ContractClassId(0x41181337),
.initializationHash = FF(0x111111),
.publicKeys = {
.masterNullifierPublicKey = AffinePoint(
Expand All @@ -74,7 +75,8 @@ TEST(AvmInputsTest, Deserialization)
.exists = false,
.salt = FF(0xdead0000),
.deployer = AztecAddress(0x000020),
.contractClassId = ContractClassId(0x51181337),
.currentContractClassId = ContractClassId(0x51181337),
.originalContractClassId = ContractClassId(0x51181337),
.initializationHash = FF(0x222222),
.publicKeys = {
.masterNullifierPublicKey = AffinePoint(
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ContractInstance HintedRawDataDB::get_contract_instance(const AztecAddress& addr
.address = contract_instance_hint.address,
.salt = contract_instance_hint.salt,
.deployer_addr = contract_instance_hint.deployer,
.contract_class_id = contract_instance_hint.contractClassId,
.contract_class_id = contract_instance_hint.originalContractClassId,
.initialisation_hash = contract_instance_hint.initializationHash,
.public_keys =
PublicKeys{
Expand Down
7 changes: 7 additions & 0 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ library Constants {
24399338136397901754495080759185489776044879232766421623673792970137;
uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE =
14061769416655647708490531650437236735160113654556896985372298487345;
uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_UPDATED_MAGIC_VALUE =
1534834688047131268740281708431107902615560100979874281215533519862;
uint256 internal constant MAX_PROTOCOL_CONTRACTS = 7;
uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS = 1;
uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = 2;
Expand All @@ -122,6 +124,10 @@ library Constants {
uint256 internal constant FEE_JUICE_ADDRESS = 5;
uint256 internal constant ROUTER_ADDRESS = 6;
uint256 internal constant FEE_JUICE_BALANCES_SLOT = 1;
uint256 internal constant UPDATED_CLASS_IDS_SLOT = 1;
uint256 internal constant SHARED_MUTABLE_VALUE_CHANGE_SEPARATOR = 0;
uint256 internal constant SHARED_MUTABLE_DELAY_CHANGE_SEPARATOR = 1;
uint256 internal constant SHARED_MUTABLE_HASH_SEPARATOR = 2;
uint256 internal constant DEFAULT_NPK_M_X =
582240093077765400562621227108555700500271598878376310175765873770292988861;
uint256 internal constant DEFAULT_NPK_M_Y =
Expand Down Expand Up @@ -305,4 +311,5 @@ library Constants {
uint256 internal constant PROOF_TYPE_ROLLUP_HONK = 5;
uint256 internal constant PROOF_TYPE_ROOT_ROLLUP_HONK = 6;
uint256 internal constant TWO_POW_64 = 18446744073709551616;
uint256 internal constant DEFAULT_UPDATE_DELAY = 10;
}
Loading
Loading