-
Notifications
You must be signed in to change notification settings - Fork 310
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: PXE db contract store #10867
Merged
Merged
feat: PXE db contract store #10867
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
7580bfb
feat: PXE db contract store
benesjan 0efdacd
WIP
benesjan 696d160
WIP
benesjan 5fec103
WIP
benesjan 1bb627a
WIP
benesjan ef02473
fixes
benesjan 764bbc3
docs cleanup
benesjan c74fd15
pxe_store --> pxe_db
benesjan e148cf0
allowing for empty arrays
benesjan 055fa87
fix
benesjan 76e1af5
using serde traits
benesjan 958c89b
contract address as arg
benesjan 822d526
fix
benesjan cf4a8cc
WIP on returning an Option
benesjan 0a9cfcc
nicer error
benesjan 13bff73
WIP on TXE tests
benesjan 4022abc
WIP on TXE tests
benesjan 5607643
handling empty return value
benesjan 5a096b0
WIP on TXE test
benesjan c7cff64
WIP
benesjan 16b0150
fix
benesjan f5519ce
overwriting test
benesjan 81312e3
WIP on using Option<T> return type
benesjan 7424970
making response always flat
benesjan e901f8a
attempt at making oracle.ts behave
benesjan daf96e1
fix
benesjan c96105e
cleanup
benesjan aaf070f
Update yarn-project/txe/src/txe_service/txe_service.ts
benesjan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}}; | ||
|
||
#[oracle(store)] | ||
unconstrained fn store_oracle<let N: u32>( | ||
contract_address: AztecAddress, | ||
key: Field, | ||
values: [Field; N], | ||
) {} | ||
|
||
/// Store a value of type T that implements Serialize in local PXE database. The data is scoped to the current | ||
/// contract. If the data under the key already exists, it is overwritten. | ||
pub unconstrained fn store<T, let N: u32>(contract_address: AztecAddress, key: Field, value: T) | ||
where | ||
T: Serialize<N>, | ||
{ | ||
let serialized = value.serialize(); | ||
store_oracle(contract_address, key, serialized); | ||
} | ||
|
||
/// Load data from local PXE database. We pass in `t_size` as a parameter to have the information of how many fields | ||
/// we need to pad if the key does not exist (note that the actual response size is `t_size + 1` as the Option prefixes | ||
/// the response with a boolean indicating if the data exists). | ||
/// | ||
/// Note that we need to return an Option<[Field; N]> as we cannot return an Option<T> directly. This is because then | ||
/// the shape of T would affect the expected oracle response (e.g. if we were returning a struct of 3 u32 values | ||
/// then the expected response shape would be 3 single items. If instead we had a struct containing | ||
/// `u32, [Field;10], u32`, then the expected shape would be single, array, single.). | ||
#[oracle(load)] | ||
unconstrained fn load_oracle<let N: u32>( | ||
contract_address: AztecAddress, | ||
key: Field, | ||
t_size: u32, | ||
) -> Option<[Field; N]> {} | ||
|
||
/// Load a value of type T that implements Deserialize from local PXE database. The data is scoped to the current | ||
/// contract. If the key does not exist, Option::none() is returned. | ||
pub unconstrained fn load<T, let N: u32>(contract_address: AztecAddress, key: Field) -> Option<T> | ||
where | ||
T: Deserialize<N>, | ||
{ | ||
let serialized_option = load_oracle::<N>(contract_address, key, N); | ||
serialized_option.map(|arr| Deserialize::deserialize(arr)) | ||
} | ||
|
||
mod test { | ||
use crate::{ | ||
oracle::{pxe_db::{load, store}, random::random}, | ||
test::{helpers::test_environment::TestEnvironment, mocks::mock_struct::MockStruct}, | ||
}; | ||
|
||
#[test] | ||
unconstrained fn stores_loads_and_overwrites_data() { | ||
let env = TestEnvironment::new(); | ||
|
||
let contract_address = env.contract_address(); | ||
let key = random(); | ||
let value = MockStruct::new(5, 6); | ||
store(contract_address, key, value); | ||
|
||
let loaded_value: MockStruct = load(contract_address, key).unwrap(); | ||
|
||
assert(loaded_value == value, "Stored and loaded values should be equal"); | ||
|
||
// Now we test that the value gets overwritten correctly. | ||
let new_value = MockStruct::new(7, 8); | ||
store(contract_address, key, new_value); | ||
|
||
let loaded_value: MockStruct = load(contract_address, key).unwrap(); | ||
|
||
assert(loaded_value == new_value, "Stored and loaded values should be equal"); | ||
} | ||
|
||
#[test] | ||
unconstrained fn load_non_existent_key() { | ||
let env = TestEnvironment::new(); | ||
|
||
let contract_address = env.contract_address(); | ||
let key = random(); | ||
let loaded_value: Option<MockStruct> = load(contract_address, key); | ||
|
||
assert(loaded_value == Option::none(), "Value should not exist"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Fr, type Wallet } from '@aztec/aztec.js'; | ||
import { TestContract } from '@aztec/noir-contracts.js/Test'; | ||
|
||
import { jest } from '@jest/globals'; | ||
|
||
import { setup } from './fixtures/utils.js'; | ||
|
||
const TIMEOUT = 120_000; | ||
|
||
// TODO(#10724): Nuke this once the linked issue is implemented (then the code will be well-tested). There is also | ||
// a TXE test in `pxe_db.nr` but I decided to keep this ugly test around as it tests the PXE oracle callback handler | ||
// (which is not tested by the TXE test). Dont't forget to remove `store_in_pxe_db` and `load_from_pxe_db` from | ||
// the test contract when removing this test. | ||
describe('PXE db', () => { | ||
jest.setTimeout(TIMEOUT); | ||
|
||
let teardown: () => Promise<void>; | ||
|
||
let testContract: TestContract; | ||
|
||
beforeAll(async () => { | ||
let wallet: Wallet; | ||
({ teardown, wallet } = await setup(1)); | ||
testContract = await TestContract.deploy(wallet).send().deployed(); | ||
}); | ||
|
||
afterAll(() => teardown()); | ||
|
||
it('stores and loads data', async () => { | ||
// In this test we feed arbitrary struct to a test contract, the test contract stores it in the PXE db and then | ||
// we load it back. | ||
const arbitraryStruct = { | ||
a: Fr.random(), | ||
b: Fr.random(), | ||
}; | ||
|
||
const key = 6n; | ||
await testContract.methods.store_in_pxe_db(key, arbitraryStruct).simulate(); | ||
|
||
// Now we try to load the data back from the PXE db. | ||
const expectedReturnValue = [arbitraryStruct.a, arbitraryStruct.b].map(v => v.toBigInt()); | ||
expect(await testContract.methods.load_from_pxe_db(key).simulate()).toEqual(expectedReturnValue); | ||
}); | ||
|
||
it('handles non-existent data', async () => { | ||
// In this test we try to load a key from the PXE db that does not exist. We should get an array of zeros. | ||
const key = 7n; | ||
expect(await testContract.methods.load_from_pxe_db(key).simulate()).toEqual([0n, 0n]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very clear, thanks for the writeup.