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

[TS SDK] Changes to add mutable field to Object Args #7991

Merged
merged 4 commits into from
Feb 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
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.
666lcz marked this conversation as resolved.
Show resolved Hide resolved
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>',
},
},
666lcz marked this conversation as resolved.
Show resolved Hide resolved
SharedObjectRef: {
healthydeve marked this conversation as resolved.
Show resolved Hide resolved
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