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

Compute next state from rust library #25

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion packages/native-utils/common/src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct SignedStateVarsWithHash {
pub signature: RecoverableSignature
}

#[derive(Deserialize)]
#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Channel {
pub chain_id: Uint256,
Expand Down
28 changes: 21 additions & 7 deletions packages/native-utils/common/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::types::*;
use super::utils::*;
use super::channel::*;

#[derive(Deserialize,PartialEq)]
#[derive(Deserialize,Serialize,PartialEq,Clone)]
#[serde(rename_all = "camelCase")]
pub struct AllocationItem {
pub destination: Bytes32,
Expand Down Expand Up @@ -39,7 +39,7 @@ impl Tokenize for AssetOutcomeType {
}
}

#[derive(Deserialize,PartialEq)]
#[derive(Deserialize, Serialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct AllocationAssetOutcome {
pub asset_holder_address: Address,
Expand All @@ -55,7 +55,7 @@ impl Tokenize for AllocationAssetOutcome {
}
}

#[derive(Deserialize, Serialize, PartialEq)]
#[derive(Deserialize, Serialize, PartialEq,Clone)]
#[serde(rename_all = "camelCase")]
pub struct Guarantee {
pub target_channel_id: Bytes32,
Expand All @@ -71,7 +71,7 @@ impl Tokenize for Guarantee {
}
}

#[derive(Deserialize,PartialEq)]
#[derive(Deserialize,Serialize,PartialEq,Clone)]
#[serde(rename_all = "camelCase")]
pub struct GuaranteeAssetOutcome {
pub asset_holder_address: Address,
Expand All @@ -87,7 +87,7 @@ impl Tokenize for GuaranteeAssetOutcome {
}
}

#[derive(Deserialize, PartialEq)]
#[derive(Deserialize, Serialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum AssetOutcome {
AllocationAssetOutcome(AllocationAssetOutcome),
Expand All @@ -107,7 +107,7 @@ impl Tokenize for AssetOutcome {
}
}

#[derive(Deserialize, PartialEq)]
#[derive(Deserialize, Serialize, PartialEq, Clone)]
#[serde(transparent)]
pub struct Outcome(Vec<AssetOutcome>);

Expand All @@ -123,7 +123,7 @@ impl Tokenize for Outcome {
}
}

#[derive(Deserialize)]
#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct State {
pub turn_num: Uint48,
Expand Down Expand Up @@ -215,6 +215,20 @@ impl State {
}
}

pub fn compute_next_state(&self, app_data: Bytes, outcome: Outcome) -> Result<State, &'static str> {
if self.turn_num.0 < 3 {
Err("State not in running stage")
} else {
let mut next_state = self.clone();
next_state.turn_num.0 = self.turn_num.0 + 1;
next_state.app_data = app_data.clone();
if !self.is_final {
next_state.outcome = outcome.clone();
}
Ok(next_state)
}
}

fn _require_extra_implicit_checks(&self, to_state: &State) -> Result<(), &'static str> {
if &self.turn_num.0 + 1 != to_state.turn_num.0 {
Err("turnNum must increment by one")
Expand Down
21 changes: 17 additions & 4 deletions packages/native-utils/common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::str::FromStr;
use ethereum_types::U256;
use serde::de::{Error as SerdeError, *};
use serde::ser::*;
use serde_derive::*;

use super::tokenize::*;

Expand All @@ -19,7 +20,7 @@ impl ToHexString for Vec<u8> {
}
}

#[derive(PartialEq)]
#[derive(PartialEq, Clone)]
pub struct Bytes(pub Vec<u8>);

impl Deref for Bytes {
Expand Down Expand Up @@ -56,7 +57,7 @@ impl Tokenize for Bytes {
}
}

#[derive(PartialEq)]
#[derive(PartialEq,Clone)]
pub struct Bytes32(Vec<u8>);

impl From<[u8; 32]> for Bytes32 {
Expand Down Expand Up @@ -109,7 +110,7 @@ impl Tokenize for Bytes32 {
}
}

#[derive(PartialEq, PartialOrd)]
#[derive(PartialEq, PartialOrd, Clone)]
pub struct Uint48(pub u64);

impl<'de> Deserialize<'de> for Uint48 {
Expand All @@ -121,13 +122,25 @@ impl<'de> Deserialize<'de> for Uint48 {
}
}

impl Serialize for Uint48 {
fn serialize<S>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u64(self.0)
}
}

impl Tokenize for Uint48 {
fn tokenize(&self) -> Token {
Token::Uint(self.0.into())
}
}

#[derive(PartialEq)]
#[derive(PartialEq, Serialize, Clone)]
pub struct Uint256(pub U256);

impl From<U256> for Uint256 {
Expand Down
13 changes: 11 additions & 2 deletions packages/native-utils/lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bytes32, Channel, State } from '@statechannels/nitro-protocol'
import { Bytes32, Channel, Outcome, State } from '@statechannels/nitro-protocol'

/**
* A Nitro state with its state hash and signature from signing the state.
Expand Down Expand Up @@ -95,4 +95,13 @@ export function recoverAddress(state: State, signature: string): string
* @param peer_update Next state suggested by peer
* @param signature Peer's signature for next state.
*/
export function validatePeerUpdate(state, peer_update, signature): string
export function validatePeerUpdate(state, peer_update, signature): string

/**
* Get My state from last state.
*
* @param last_state A Nitro state.
* @param app_data App data
* @param outcome Outcome
*/
export function computeNextState(last_state: State, app_data: String, outcome: Outcome): State
3 changes: 3 additions & 0 deletions packages/native-utils/lib/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
recoverAddress,
verifySignature,
validatePeerUpdate,
computeNextState,
} = require('../native/index.node')

function unwrapResult({ Ok, Err }) {
Expand Down Expand Up @@ -46,4 +47,6 @@ module.exports = {
verifySignature: (hash, address, signature) => unwrapResult(verifySignature(hash, address, signature)),

validatePeerUpdate: (state, peer_update, signature) => unwrapResult(validatePeerUpdate(state, peer_update, signature)),

computeNextState: (last_state, app_data, outcome) => unwrapResult(computeNextState(last_state, app_data, outcome)),
}
4 changes: 3 additions & 1 deletion packages/native-utils/lib/index.wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const {
signState,
recoverAddress,
verifySignature,
validatePeerUpdate,
validatePeerUpdate,
computeNextState,
} = require('@statechannels/wasm-utils')

module.exports = {
Expand All @@ -36,4 +37,5 @@ module.exports = {
recoverAddress,
verifySignature,
validatePeerUpdate,
computeNextState,
}
4 changes: 4 additions & 0 deletions packages/native-utils/native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ export! {
fn validatePeerUpdate(state: State, peer_update: State, peer_signature: Bytes) -> Result<Status, &'static str> {
state.validate_peer_update(peer_update, peer_signature)
}

fn computeNextState(last_state: State, app_data: Bytes, outcome: Outcome) -> Result<State, &'static str> {
last_state.compute_next_state(app_data, outcome)
}
}
33 changes: 33 additions & 0 deletions packages/native-utils/tests/transition.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,37 @@ describe('Validate state transitions', () => {
expect(() => native.validatePeerUpdate(currentState, peerState, nativeSigned.signature)).toThrow('Outcome change forbidden');
expect(() => wasm.validatePeerUpdate(currentState, peerState, nativeSigned.signature)).toThrow('Outcome change forbidden');
})

test('Compute next state', async () => {
const otheroutcome = [
{
assetHolderAddress: '0x0000000000000000000000000000000000000000',
guarantee: {
targetChannelId:
'0x0000000000000000000000000000000000000000000000000000000000000000',
destinations: [
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x2222222222222222222222222222222222222222222222220222222222222222',
],
},
},
]

let currentState = {
...CURRENT_STATE,
}

const APPDATA = '0x0000000000000000000000000000000000000000000000000000000000000001'

currentState.isFinal = false
currentState.turnNum = 5;

let nextState = native.computeNextState(currentState,APPDATA, OUTCOME)
let wasmNextState = wasm.computeNextState(currentState,APPDATA, OUTCOME)

expect(Number(nextState.channel.chainId)).toEqual(Number(currentState.channel.chainId));
expect(nextState.appData).toEqual(APPDATA);
expect(Number(wasmNextState.channel.chainId)).toEqual(Number(currentState.channel.chainId));
expect(wasmNextState.appData).toEqual(APPDATA);
})
})
12 changes: 12 additions & 0 deletions wasm-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ extern "C" {

#[wasm_bindgen(typescript_type = "StateSignature")]
pub type JsStateSignature;

#[wasm_bindgen(typescript_type = "Outcome")]
pub type JsOutcome;
}

#[wasm_bindgen(js_name = "getChannelId")]
Expand Down Expand Up @@ -88,4 +91,13 @@ pub fn validate_peer_update(state: &JsState, peer_update: &JsState, signature: &
let signature: Bytes = signature.into_serde().unwrap();
let result = state.validate_peer_update(peer_update, signature).map_err(JsValue::from)?;
Ok(JsValue::from_serde(&result).unwrap().into())
}

#[wasm_bindgen(js_name = "computeNextState")]
pub fn compute_next_state(state: &JsState, app_data: &JsString, outcome: &JsOutcome) -> Result<JsString, JsValue> {
let state: State = state.into_serde().unwrap();
let app_data: Bytes = app_data.into_serde().unwrap();
let outcome: Outcome = outcome.into_serde().unwrap();
let result = state.compute_next_state(app_data, outcome).map_err(JsValue::from)?;
Ok(JsValue::from_serde(&result).unwrap().into())
}