Skip to content

Commit

Permalink
[TS SDK] Changes to add mutable field to Object Args (MystenLabs#7991)
Browse files Browse the repository at this point in the history
reverted previous commit to ignore mutable field.

Added the new mutable field with backwards compatibility

---------

Co-authored-by: Jian Lu <[email protected]>
  • Loading branch information
healthydeve and Jian Lu authored Feb 5, 2023
1 parent e4c459f commit 7250911
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 51 deletions.
1 change: 1 addition & 0 deletions crates/sui-core/tests/staged/sui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ ObjectArg:
TYPENAME: ObjectID
- initial_shared_version:
TYPENAME: SequenceNumber
- mutable: BOOL
ObjectDigest:
NEWTYPESTRUCT: BYTES
ObjectFormatOptions:
Expand Down
6 changes: 0 additions & 6 deletions crates/sui-types/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,10 @@ pub enum ObjectArg {
SharedObject {
id: ObjectID,
initial_shared_version: SequenceNumber,
// Temporary fix until SDK will be aware of mutable flag
#[serde(skip, default = "bool_true")]
mutable: bool,
},
}

fn bool_true() -> bool {
true
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct TransferObject {
pub recipient: SuiAddress,
Expand Down
77 changes: 35 additions & 42 deletions crates/sui/tests/shared_objects_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
use futures::{stream, StreamExt};
use sui_core::authority_client::AuthorityAPI;
use sui_types::messages::{
CallArg, ExecutionStatus, ObjectArg, ObjectInfoRequest, ObjectInfoRequestKind,
CallArg, EntryArgumentError, EntryArgumentErrorKind, ExecutionFailureStatus, ExecutionStatus,
ObjectArg, ObjectInfoRequest, ObjectInfoRequestKind,
};
use test_utils::authority::get_client;
use test_utils::transaction::{
Expand Down Expand Up @@ -86,8 +87,7 @@ async fn call_shared_object_contract() {
);
let effects = submit_single_owner_transaction(transaction, configs.validator_set()).await;
assert!(matches!(effects.status, ExecutionStatus::Success { .. }));
// todo(RWLock) uncomment when serialization of mutable field is fixed
// let counter_creation_transaction = effects.transaction_digest;
let counter_creation_transaction = effects.transaction_digest;
let ((counter_id, counter_initial_shared_version, _), _) = effects.created[0];
let counter_object_arg = ObjectArg::SharedObject {
id: counter_id,
Expand Down Expand Up @@ -120,9 +120,8 @@ async fn call_shared_object_contract() {
// Only gas object transaction and counter creation are dependencies
// Note that this assert would fail for second transaction
// if they send counter_object_arg instead of counter_object_arg_imm
// todo(RWLock) uncomment when serialization of mutable field is fixed
// assert_eq!(effects.dependencies.len(), 2);
// assert!(effects.dependencies.contains(&counter_creation_transaction));
assert_eq!(effects.dependencies.len(), 2);
assert!(effects.dependencies.contains(&counter_creation_transaction));
}

// Make a transaction to increment the counter.
Expand All @@ -136,19 +135,16 @@ async fn call_shared_object_contract() {
let effects = submit_shared_object_transaction(transaction, configs.validator_set())
.await
.unwrap();
// todo(RWLock) uncomment when serialization of mutable field is fixed
// let increment_transaction = effects.transaction_digest;
let increment_transaction = effects.transaction_digest;
assert!(matches!(effects.status, ExecutionStatus::Success { .. }));
// Again - only gas object transaction and counter creation are dependencies
// Previously executed assert_value transaction(s) are not a dependency because they took immutable reference to shared object
// todo(RWLock) uncomment when serialization of mutable field is fixed
// assert_eq!(effects.dependencies.len(), 2);
// assert!(effects.dependencies.contains(&counter_creation_transaction));
assert_eq!(effects.dependencies.len(), 2);
assert!(effects.dependencies.contains(&counter_creation_transaction));

// assert_value can take both mutable and immutable references
// it is allowed to pass mutable shared object arg to move call taking immutable reference
// todo(RWLock) uncomment when serialization of mutable field is fixed
// let mut assert_value_mut_transaction = None;
let mut assert_value_mut_transaction = None;
for imm in [true, false] {
// Ensure the value of the counter is `1`.
let transaction = move_transaction(
Expand All @@ -170,39 +166,36 @@ async fn call_shared_object_contract() {
.unwrap();
assert!(matches!(effects.status, ExecutionStatus::Success { .. }));
// Gas object transaction and increment transaction are dependencies
// todo(RWLock) uncomment when serialization of mutable field is fixed
// assert_eq!(effects.dependencies.len(), 2);
// assert!(effects.dependencies.contains(&increment_transaction));
// assert_value_mut_transaction = Some(effects.transaction_digest);
assert_eq!(effects.dependencies.len(), 2);
assert!(effects.dependencies.contains(&increment_transaction));
assert_value_mut_transaction = Some(effects.transaction_digest);
}

// todo(RWLock) uncomment when serialization of mutable field is fixed
// let assert_value_mut_transaction = assert_value_mut_transaction.unwrap();
let assert_value_mut_transaction = assert_value_mut_transaction.unwrap();

// And last check - attempt to send increment transaction with immutable reference
// todo(RWLock) uncomment when serialization of mutable field is fixed
// let transaction = move_transaction(
// gas_objects.pop().unwrap(),
// "counter",
// "increment",
// package_id,
// vec![CallArg::Object(counter_object_arg_imm)],
// );
// let effects = submit_shared_object_transaction(transaction, configs.validator_set())
// .await
// .unwrap();
// // Transaction fails
// assert!(matches!(
// effects.status,
// ExecutionStatus::Failure {
// error: ExecutionFailureStatus::EntryArgumentError(EntryArgumentError {
// kind: EntryArgumentErrorKind::ObjectMutabilityMismatch,
// ..
// })
// }
// ));
// assert_eq!(effects.dependencies.len(), 2);
// assert!(effects.dependencies.contains(&assert_value_mut_transaction));
let transaction = move_transaction(
gas_objects.pop().unwrap(),
"counter",
"increment",
package_id,
vec![CallArg::Object(counter_object_arg_imm)],
);
let effects = submit_shared_object_transaction(transaction, configs.validator_set())
.await
.unwrap();
// Transaction fails
assert!(matches!(
effects.status,
ExecutionStatus::Failure {
error: ExecutionFailureStatus::EntryArgumentError(EntryArgumentError {
kind: EntryArgumentErrorKind::ObjectMutabilityMismatch,
..
})
}
));
assert_eq!(effects.dependencies.len(), 2);
assert!(effects.dependencies.contains(&assert_value_mut_transaction));
}

/// Same test as `call_shared_object_contract` but the clients submits many times the same
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,17 @@ export class CallArgSerializer {
async newObjectArg(objectId: string): Promise<ObjectArg> {
const object = await this.provider.getObject(objectId);
const initialSharedVersion = getSharedObjectInitialVersion(object);

const mutable = true; // Defaulted to True to match current behavior.
const api = await this.provider.getRpcApiVersion();

if (initialSharedVersion) {
return { Shared: { objectId, initialSharedVersion } };
const object_args =
api?.major === 0 && api?.minor < 25
? { Shared: { objectId, initialSharedVersion } }
: { Shared: { objectId, initialSharedVersion, mutable } };
return object_args;
}

return { ImmOrOwned: getObjectReference(object)! };
}

Expand Down
41 changes: 40 additions & 1 deletion sdk/typescript/src/types/sui-bcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,28 @@ export type SharedObjectRef = {

/** The version the object was shared at */
initialSharedVersion: number;

/** Whether reference is mutable */
mutable: boolean;
};

/**
* A reference to a shared object from 0.23.0.
*/
export type SharedObjectRef_23 = {
/** Hex code as string representing the object id */
objectId: string;

/** The version the object was shared at */
initialSharedVersion: number;
};

/**
* An object argument.
*/
export type ObjectArg =
| { ImmOrOwned: SuiObjectRef }
| { Shared: SharedObjectRef };
| { Shared: SharedObjectRef | SharedObjectRef_23 };

/**
* A pure argument.
Expand Down Expand Up @@ -329,6 +343,7 @@ const BCS_SPEC = {
struct: {
objectId: 'address',
initialSharedVersion: 'u64',
mutable: 'bool',
},
},

Expand Down Expand Up @@ -431,6 +446,22 @@ const BCS_0_23_SPEC = {
arguments: 'vector<CallArg>',
},
},
SharedObjectRef: {
struct: {
objectId: 'address',
initialSharedVersion: 'u64',
},
},
};

const BCS_0_24_SPEC = {
...BCS_SPEC,
SharedObjectRef: {
struct: {
objectId: 'address',
initialSharedVersion: 'u64',
},
},
};

const bcs = new BCS(getSuiMoveConfig());
Expand All @@ -444,9 +475,17 @@ registerUTF8String(bcs_0_23);
registerObjectDigest(bcs_0_23);
registerTypes(bcs_0_23, BCS_0_23_SPEC);

const bcs_0_24 = new BCS(getSuiMoveConfig());
registerUTF8String(bcs_0_24);
registerObjectDigest(bcs_0_24);
registerTypes(bcs_0_24, BCS_0_24_SPEC);

export function bcsForVersion(v?: RpcApiVersion) {
if (v?.major === 0 && v?.minor < 24) {
return bcs_0_23;
}
if (v?.major === 0 && v?.minor === 24) {
return bcs_0_24;
} else {
return bcs;
}
Expand Down

0 comments on commit 7250911

Please sign in to comment.