Skip to content

Commit

Permalink
Fixed parsing ByteArray for schema (#12)
Browse files Browse the repository at this point in the history
Co-authored-by: Vladimir Kuchinskiy <[email protected]>
  • Loading branch information
Volodymyr-Kuchinskyi and Vladimir Kuchinskiy authored Feb 28, 2023
1 parent ecd5217 commit d6b9526
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 11 deletions.
13 changes: 12 additions & 1 deletion package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
}
},
"dependencies": {
"casper-js-sdk": "^2.11.0"
"casper-js-sdk": "^2.11.0",
"ts-results": "^3.3.0"
},
"devDependencies": {
"@types/jest": "^29.4.0",
Expand Down
184 changes: 183 additions & 1 deletion src/casper/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
import { matchBytesToCLType } from 'casper-js-sdk';
import {
CLBoolType,
CLByteArrayType,
CLI32Type,
CLI64Type,
CLKeyType,
CLListType,
CLMapType,
CLOptionType,
CLPublicKeyType,
CLResultType,
CLStringType,
CLTuple1Type,
CLType,
CLTypeTag,
CLU128Type,
CLU256Type,
CLU32BytesParser,
CLU32Type,
CLU512Type,
CLU64Type,
CLU8Type,
CLUnitType,
CLURefType,
ResultAndRemainder,
resultHelper,
} from 'casper-js-sdk';
import { Err, Ok } from 'ts-results';
import { RawCLValue, WithRemainder } from './types';

export function parseBytesWithRemainder(
Expand Down Expand Up @@ -43,3 +70,158 @@ export function parseCLValueFromBytesWithRemainder(
remainder: clTypeWithRemainder.remainder,
};
}

export function matchBytesToCLType(
bytes: Uint8Array,
): ResultAndRemainder<CLType, string> {
const tag = bytes[0];
const remainder = bytes.subarray(1);

switch (tag) {
case CLTypeTag.Bool:
return resultHelper(Ok(new CLBoolType()), remainder);
case CLTypeTag.I32:
return resultHelper(Ok(new CLI32Type()), remainder);
case CLTypeTag.I64:
return resultHelper(Ok(new CLI64Type()), remainder);
case CLTypeTag.U8:
return resultHelper(Ok(new CLU8Type()), remainder);
case CLTypeTag.U32:
return resultHelper(Ok(new CLU32Type()), remainder);
case CLTypeTag.U64:
return resultHelper(Ok(new CLU64Type()), remainder);
case CLTypeTag.U64:
return resultHelper(Ok(new CLU64Type()), remainder);
case CLTypeTag.U128:
return resultHelper(Ok(new CLU128Type()), remainder);
case CLTypeTag.U256:
return resultHelper(Ok(new CLU256Type()), remainder);
case CLTypeTag.U512:
return resultHelper(Ok(new CLU512Type()), remainder);
case CLTypeTag.Unit:
return resultHelper(Ok(new CLUnitType()), remainder);
case CLTypeTag.String:
return resultHelper(Ok(new CLStringType()), remainder);
case CLTypeTag.Key:
return resultHelper(Ok(new CLKeyType()), remainder);
case CLTypeTag.URef:
return resultHelper(Ok(new CLURefType()), remainder);
case CLTypeTag.Option: {
const { result, remainder: typeRem } = matchBytesToCLType(remainder);

const innerType = result.unwrap();

return resultHelper(Ok(new CLOptionType(innerType)), typeRem);
}
case CLTypeTag.List: {
const { result, remainder: typeRem } = matchBytesToCLType(remainder);

const innerType = result.unwrap();

return resultHelper(Ok(new CLListType(innerType)), typeRem);
}
case CLTypeTag.ByteArray: {
const { result: sizeRes, remainder: rem } =
new CLU32BytesParser().fromBytesWithRemainder(remainder);

const size = sizeRes.unwrap().value().toNumber();

return resultHelper(Ok(new CLByteArrayType(size)), rem);
}
case CLTypeTag.Result: {
const { result: okTypeRes, remainder: okTypeRem } =
matchBytesToCLType(remainder);
const okType = okTypeRes.unwrap();

if (!okTypeRem)
return resultHelper(Err('Missing Error type bytes in Result'));

const { result: errTypeRes, remainder: rem } =
matchBytesToCLType(okTypeRem);
const errType = errTypeRes.unwrap();

return resultHelper(
Ok(new CLResultType({ ok: okType, err: errType })),
rem,
);
}
case CLTypeTag.Map: {
const { result: keyTypeRes, remainder: keyTypeRem } =
matchBytesToCLType(remainder);
const keyType = keyTypeRes.unwrap();

if (!keyTypeRem)
return resultHelper(Err('Missing Key type bytes in Map'));

const { result: valTypeRes, remainder: rem } =
matchBytesToCLType(keyTypeRem);
const valType = valTypeRes.unwrap();

return resultHelper(Ok(new CLMapType([keyType, valType])), rem);
}
case CLTypeTag.Tuple1: {
const { result: innerTypeRes, remainder: rem } =
matchBytesToCLType(remainder);
const innerType = innerTypeRes.unwrap();

return resultHelper(Ok(new CLTuple1Type([innerType])), rem);
}
case CLTypeTag.Tuple2: {
const { result: innerType1Res, remainder: innerType1Rem } =
matchBytesToCLType(remainder);
const innerType1 = innerType1Res.unwrap();

if (!innerType1Rem) {
return resultHelper(
Err('Missing second tuple type bytes in CLTuple2Type'),
);
}

const { result: innerType2Res, remainder: innerType2Rem } =
matchBytesToCLType(innerType1Rem);
const innerType2 = innerType2Res.unwrap();

return resultHelper(
Ok(new CLTuple1Type([innerType1, innerType2])),
innerType2Rem,
);
}
case CLTypeTag.Tuple3: {
const { result: innerType1Res, remainder: innerType1Rem } =
matchBytesToCLType(remainder);
const innerType1 = innerType1Res.unwrap();

if (!innerType1Rem) {
return resultHelper(
Err('Missing second tuple type bytes in CLTuple2Type'),
);
}

const { result: innerType2Res, remainder: innerType2Rem } =
matchBytesToCLType(innerType1Rem);
const innerType2 = innerType2Res.unwrap();

if (!innerType2Rem) {
return resultHelper(
Err('Missing third tuple type bytes in CLTuple2Type'),
);
}

const { result: innerType3Res, remainder: innerType3Rem } =
matchBytesToCLType(innerType2Rem);
const innerType3 = innerType3Res.unwrap();

return resultHelper(
Ok(new CLTuple1Type([innerType1, innerType2, innerType3])),
innerType3Rem,
);
}
case CLTypeTag.Any: {
return resultHelper(Err('Any unsupported'));
}
case CLTypeTag.PublicKey:
return resultHelper(Ok(new CLPublicKeyType()), remainder);
}

return resultHelper(Err('Unsuported type'));
}
9 changes: 2 additions & 7 deletions src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import {
CasperServiceByJsonRPC,
CLType,
decodeBase16,
matchBytesToCLType,
} from 'casper-js-sdk';
import { CasperServiceByJsonRPC, CLType, decodeBase16 } from 'casper-js-sdk';
import { WithRemainder } from './casper/types';
import { parseBytesWithRemainder } from './casper/utils';
import { matchBytesToCLType, parseBytesWithRemainder } from './casper/utils';
import { EVENTS_SCHEMA_NAMED_KEY } from './parser';

export type Schemas = Record<string, Schema>;
Expand Down
19 changes: 18 additions & 1 deletion test/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('Schema', () => {
expect(schema.data[1].value.tag).toEqual(CLTypeTag.Key);
});

it('should parse schema from raw bytes with option conmplex type', () => {
it('should parse schema from raw bytes with option complex type', () => {
const hexStr = '01000000060000006f7074696f6e0d0b';
const schema = parseSchemaFromBytesWithRemainder(decodeBase16(hexStr));

Expand All @@ -47,5 +47,22 @@ describe('Schema', () => {
CLTypeTag.Key,
);
});

it('should parse schema from raw bytes with byte array type', () => {
const hexStr =
'030000000a000000636f6c6c656374696f6e0f2000000008000000746f6b656e5f696407070000006f6666657265720b';
const schema = parseSchemaFromBytesWithRemainder(decodeBase16(hexStr));

expect(schema.data.length).toEqual(3);

expect(schema.data[0].property).toEqual('collection');
expect(schema.data[0].value.tag).toEqual(CLTypeTag.ByteArray);

expect(schema.data[1].property).toEqual('token_id');
expect(schema.data[1].value.tag).toEqual(CLTypeTag.U256);

expect(schema.data[2].property).toEqual('offerer');
expect(schema.data[2].value.tag).toEqual(CLTypeTag.Key);
});
});
});

0 comments on commit d6b9526

Please sign in to comment.