Skip to content

Commit

Permalink
Merge pull request #28 from Concordium/add-deserialization-of-contrac…
Browse files Browse the repository at this point in the history
…t-state

Add deserialization of contract state
  • Loading branch information
shjortConcordium authored Feb 10, 2022
2 parents 17342bb + e8b3f76 commit 39795af
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 6 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
[submodule "deps/concordium-base"]
path = deps/concordium-base
url = https://github.com/Concordium/concordium-base.git
[submodule "deps/concordium-contracts-common"]
path = deps/concordium-contracts-common
url = https://github.com/Concordium/concordium-contracts-common.git

3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Changelog

## Unreleased
## 0.6.0 2022-02-02

### Added

- Function to deserialize contract state.
- Support for register data transaction.

## 0.5.1 2021-11-19
Expand Down
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ version = "0"
path = "deps/concordium-base/rust-src/ps_sig"
version = "0"

[dependencies.concordium-contracts-common]
features = ["derive-serde"]
path = "deps/concordium-contracts-common"
version = "2.0.0"

[lib]
name = "node_sdk_helpers"
crate-type = ["cdylib"]
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,16 @@ const updateContractTransaction: AccountTransaction = {

Finally, to actually update the contract on the chain, send the constructed `updateContractTransaction` to the chain using `sendAccountTransaction`. (See [Send Account Transaction](#Send-Account-Transaction) for how to do this)

## Deserialize contract state
The following example demonstrates how to deserialize a contract's state:

```js
const contractName = "my-contract-name"
const schema = Buffer.from(schemaSource); // Load schema from file
const rawContractState = Buffer.from(stateSource); // Could be getinstanceInfo(...).model
const state = deserializeContractState(contractName, schema, rawContractState);
```

# Build

## Building for a release
Expand Down
1 change: 1 addition & 0 deletions deps/concordium-contracts-common
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@concordium/node-sdk",
"version": "0.5.1",
"version": "0.6.0",
"description": "Helpers for interacting with the Concordium node",
"repository": {
"type": "git",
Expand Down
28 changes: 24 additions & 4 deletions rust-src/aux_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ use std::collections::BTreeMap;
type ExampleCurve = G1;
use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
use sha2::{Digest, Sha256};
use concordium_contracts_common::{from_bytes, Cursor, schema};
use hex;

use anyhow::{bail, Result, anyhow};
use id::{account_holder::create_unsigned_credential, constants::AttributeKind, types::*};
use pedersen_scheme::Value;

#[derive(SerdeSerialize, SerdeDeserialize)]
pub struct CredId {
Expand All @@ -18,10 +24,6 @@ pub struct CredId {
pub cred_id: ExampleCurve,
}

use anyhow::{bail, Result};
use id::{account_holder::create_unsigned_credential, constants::AttributeKind, types::*};
use pedersen_scheme::Value;

pub fn generate_unsigned_credential_aux(input: &str) -> Result<String> {
let v: SerdeValue = from_str(input)?;
let ip_info: IpInfo<Bls12> = try_get(&v, "ipInfo")?;
Expand Down Expand Up @@ -176,3 +178,21 @@ pub fn get_credential_deployment_info_aux(
let cdi_json = json!(cdi);
Ok(cdi_json.to_string())
}

/// Given the bytes of a contract's state, deserialize them to a json object, using the provided schema.
/// Both the state bytes and the schema are given as hex-encoded strings.
pub fn deserialize_state_aux(
contract_name: &str,
state_bytes: String,
schema: String,
) -> Result<String> {
let module_schema: schema::Module = match from_bytes(&hex::decode(schema)?) {
Ok(o) => o,
Err(e) => return Err(anyhow!("unable to parse schema: {:#?}", e))
};
let mut state_cursor = Cursor::new(hex::decode(state_bytes)?);
let contract_schema = module_schema.contracts.get(contract_name).ok_or(anyhow!("Unable to get contract schema: not included in module schema"))?;
let state_schema = contract_schema.state.as_ref().ok_or(anyhow!("Unable to get state schema: not included in contract schema"))?;
Ok(state_schema.to_json(&mut state_cursor).expect("Unable to parse state to json").to_string())
}

13 changes: 13 additions & 0 deletions rust-src/external_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,16 @@ pub fn get_credential_deployment_info_ext(
Err(e) => format!("unable to get credential due to: {}", e),
}
}

#[wasm_bindgen(js_name = deserializeState)]
pub fn deserialize_state(
contract_name: &str,
state_bytes: String,
schema: String,
) -> String {
match deserialize_state_aux(contract_name, state_bytes, schema) {
Ok(s) => s.to_string(),
Err(e) => format!("{}", e),
}
}

26 changes: 26 additions & 0 deletions src/deserialization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as wasm from '../pkg/node_sdk_helpers';
import { Buffer } from 'buffer/';

/**
* Given a contract's raw state, its name and its schema, return the state as a JSON object.
* The return type is any, and the actual type should be determined by using the schema.
*/
export function deserializeContractState(
contractName: string,
schema: Buffer,
state: Buffer
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): any {
const serializedState = wasm.deserializeState(
contractName,
state.toString('hex'),
schema.toString('hex')
);
try {
return JSON.parse(serializedState);
} catch (e) {
throw new Error(
'unable to deserialize state, due to: ' + serializedState
); // In this case serializedState is the error message from the rust module
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ export {
buildSignedCredentialForExistingAccount,
} from './credentialDeploymentTransactions';
export { isAlias, getAlias } from './alias';
export { deserializeContractState } from './deserialization';
40 changes: 40 additions & 0 deletions test/deserialization.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { getNodeClient } from './testHelpers';
import { deserializeContractState } from '../src/deserialization';
import { Buffer } from 'buffer/';
import * as fs from 'fs';

const client = getNodeClient();

test('Deserialize state with schema from file (two-step-transfer)', async () => {
const blockHash =
'fad0981b0424c6e1af746a39667628861481ac225f90decd233980311c2e19cb';
const contractAddress = { index: BigInt(1646), subindex: BigInt(0) };

const instanceInfo = await client.getInstanceInfo(
blockHash,
contractAddress
);
if (!instanceInfo) {
throw new Error(
'The instance info should exist for the provided block hash.'
);
}
const schema = Buffer.from(
fs.readFileSync('./test/resources/two-step-transfer-schema.bin')
);
const state = deserializeContractState(
'two-step-transfer',
schema,
instanceInfo.model
);
expect(state.init_params.transfer_agreement_threshold).toBe(2);
expect(state.init_params.account_holders.length).toBe(2);
expect(state.init_params.account_holders[0]).toBe(
'3Y1RLgi5pW3x96xZ7CiDiKsTL9huU92qn6mfxpebwmtkeku8ry'
);
expect(state.init_params.account_holders[1]).toBe(
'4EdBeGmpnQZWxaiig7FGEhWwmJurYmYsPWXo6owMDxA7ZtJMMH'
);
expect(state.init_params.transfer_request_ttl).toBe('0d 0h 0m 0s 0ms');
expect(state.requests.length).toBe(0);
});
Binary file added test/resources/two-step-transfer-schema.bin
Binary file not shown.

0 comments on commit 39795af

Please sign in to comment.