Skip to content

Commit e6aaba7

Browse files
author
Eduardo Leegwater Simões
committed
piecrust: optional owner in migrate
It is now optional to provide an `owner` to the `Session::migrate` call. If the owner is not specified, it will be taken from the previous contract at the slot being migrated. If the owner is not specified and the contract being replaced does not exist, the call will panic. Resolves #336
1 parent 467e69a commit e6aaba7

File tree

3 files changed

+98
-2
lines changed

3 files changed

+98
-2
lines changed

piecrust/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414

1515
### Changed
1616

17+
- Change `migrate` to take the owner of the contract being replaced if it is
18+
not set by the caller [#336]
1719
- Make `owner` field optional in `ContractData` and `ContractDataBuilder` [#336]
1820
- Change `ContractData` and `ContractDataBuilder` to take a `Vec<u8>` as owner
1921
instead of `[u8; N]` [#336]

piecrust/src/session.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,18 @@ impl Session {
406406
/// given `contract` ID, and the old contract will be removed from the
407407
/// state.
408408
///
409+
/// If the `owner` of a contract is not set, it will be set to the owner of
410+
/// the contract being replaced. If it is set, then it will be used as the
411+
/// new owner.
412+
///
409413
/// # Errors
410414
/// The migration may error during execution for a myriad of reasons. The
411415
/// caller is encouraged to drop the `Session` should an error occur as it
412416
/// will more than likely be left in an inconsistent state.
417+
///
418+
/// # Panics
419+
/// If the owner of the new contract is not set in `deploy_data`, and the
420+
/// contract being replaced does not exist, this will panic.
413421
pub fn migrate<'a, A, D, F>(
414422
mut self,
415423
contract: ContractId,
@@ -423,8 +431,25 @@ impl Session {
423431
D: Into<ContractData<'a, A>>,
424432
F: FnOnce(ContractId, &mut Session) -> Result<(), Error>,
425433
{
434+
let mut new_contract_data = deploy_data.into();
435+
436+
// If the contract being replaced exists, and the caller did not specify
437+
// an owner, set the owner to the owner of the contract being replaced.
438+
if let Some(old_contract_data) = self
439+
.inner
440+
.contract_session
441+
.contract(contract)
442+
.map_err(|err| PersistenceError(Arc::new(err)))?
443+
{
444+
if new_contract_data.owner.is_none() {
445+
new_contract_data.owner =
446+
Some(old_contract_data.metadata.data().owner.clone());
447+
}
448+
}
449+
426450
let new_contract =
427-
self.deploy(bytecode, deploy_data, deploy_gas_limit)?;
451+
self.deploy(bytecode, new_contract_data, deploy_gas_limit)?;
452+
428453
closure(new_contract, &mut self)?;
429454

430455
self.inner

piecrust/tests/persistence.rs

+70-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ fn migration() -> Result<(), Error> {
170170
session = session.migrate(
171171
contract,
172172
contract_bytecode!("double_counter"),
173-
ContractData::builder().owner(OWNER),
173+
ContractData::builder(),
174174
LIMIT,
175175
|new_contract, session| {
176176
let old_counter_value = session
@@ -208,3 +208,72 @@ fn migration() -> Result<(), Error> {
208208

209209
Ok(())
210210
}
211+
212+
#[test]
213+
fn migration_new_owner() -> Result<(), Error> {
214+
let vm = VM::ephemeral()?;
215+
let mut session = vm.session(SessionData::builder())?;
216+
217+
const OWNER: [u8; 33] = [1u8; 33];
218+
const NEW_OWNER: [u8; 33] = [2u8; 33];
219+
220+
let contract = session.deploy(
221+
contract_bytecode!("counter"),
222+
ContractData::builder().owner(OWNER),
223+
LIMIT,
224+
)?;
225+
226+
let root = session.commit()?;
227+
228+
let mut session = vm.session(SessionData::builder().base(root))?;
229+
230+
session = session.migrate(
231+
contract,
232+
contract_bytecode!("metadata"),
233+
ContractData::builder().owner(NEW_OWNER),
234+
LIMIT,
235+
|_, _| Ok(()),
236+
)?;
237+
238+
let owner = session
239+
.call::<_, [u8; 33]>(contract, "read_owner", &(), LIMIT)?
240+
.data;
241+
242+
assert_eq!(owner, NEW_OWNER);
243+
244+
Ok(())
245+
}
246+
247+
#[test]
248+
fn migration_old_owner() -> Result<(), Error> {
249+
let vm = VM::ephemeral()?;
250+
let mut session = vm.session(SessionData::builder())?;
251+
252+
const OWNER: [u8; 33] = [1u8; 33];
253+
254+
let contract = session.deploy(
255+
contract_bytecode!("counter"),
256+
ContractData::builder().owner(OWNER),
257+
LIMIT,
258+
)?;
259+
260+
let root = session.commit()?;
261+
262+
let mut session = vm.session(SessionData::builder().base(root))?;
263+
264+
session = session.migrate(
265+
contract,
266+
contract_bytecode!("metadata"),
267+
ContractData::builder(),
268+
LIMIT,
269+
|_, _| Ok(()),
270+
)?;
271+
272+
let owner = session
273+
.call::<_, [u8; 33]>(contract, "read_owner", &(), LIMIT)?
274+
.data;
275+
276+
assert_eq!(owner, OWNER);
277+
278+
Ok(())
279+
}

0 commit comments

Comments
 (0)