Skip to content

Commit

Permalink
throw error if conflicting variant definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-pousette committed Jun 15, 2022
1 parent 2a4676d commit ff46fc7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dao-xyz/borsh",
"version": "2.0.5",
"version": "2.0.6",
"readme": "README.md",
"homepage": "https://github.com/dao-xyz/borsh-ts#README",
"description": "Binary Object Representation Serializer for Hashing",
Expand Down
44 changes: 44 additions & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,50 @@ describe("Validation", () => {
expect(deserialize(Buffer.from(bytes), TestStruct, true).a).toEqual(1);
});

test("variant conflict, index", () => {
const classDef = () => {
class TestStruct {
constructor() {}
}
@variant(0) // Same as B
class A extends TestStruct {
constructor() {
super();
}
}

@variant(0) // Same as A
class B extends TestStruct {
constructor() {
super();
}
}
};
expect(() => classDef()).toThrowError(BorshError);
});

test("variant conflict, indices", () => {
const classDef = () => {
class TestStruct {
constructor() {}
}
@variant([0, 1, 2]) // Same as B
class A extends TestStruct {
constructor() {
super();
}
}

@variant([0, 1, 2]) // Same as A
class B extends TestStruct {
constructor() {
super();
}
}
};
expect(() => classDef()).toThrowError(BorshError);
});

test("undefined throws error", () => {
class MissingImplementation {
public someField: number;
Expand Down
42 changes: 23 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function deserializeStruct(clazz: any, reader: BinaryReader) {
// class this can be deserialized to)

// We know that we should serialize into the variant that accounts to the first byte of the read
for (const actualClazz of getDependencies(clazz)) {
for (const [_key, actualClazz] of getDependencies(clazz)) {
const variantIndex = getVariantIndex(actualClazz);
if (variantIndex !== undefined) {
if (typeof variantIndex === "number") {
Expand Down Expand Up @@ -283,30 +283,35 @@ const getOrCreateStructMeta = (clazz: any): StructKind => {
} */
}

const setDependency = (ctor: Function, depenency: Function) => {
if (!ctor.prototype._borsh_dependency) {
ctor.prototype._borsh_dependency = []
const setDependency = (ctor: Function, dependency: Function) => {
let dependencies = getDependencies(ctor);
let key = JSON.stringify(getVariantIndex(dependency));
if (dependencies.has(key)) {
throw new BorshError(`Conflicting variants: Dependency ${dependencies.get(key).name} and ${dependency.name} share same variant index(es)`)
}
ctor.prototype._borsh_dependency.push(depenency);
dependencies.set(key, dependency);
ctor.prototype._borsh_dependency = dependencies;
}

const hasDependencies = (ctor: Function, schema: Map<any, StructKind>): boolean => {
if (!ctor.prototype._borsh_dependency || ctor.prototype._borsh_dependency.length == 0) {
if (!ctor.prototype._borsh_dependency || ctor.prototype._borsh_dependency.size == 0) {
return false
}

for (const dependency of ctor.prototype._borsh_dependency) {
for (const [_key, dependency] of getDependencies(ctor)) {
if (!schema.has(dependency)) {
return false;
}
}
return true;
}

const getDependencies = (ctor: Function): Function[] => {
return ctor.prototype._borsh_dependency ? ctor.prototype._borsh_dependency : []
const getDependencies = (ctor: Function): Map<string, Function> => {
return ctor.prototype._borsh_dependency ? ctor.prototype._borsh_dependency : new Map();
}



const setSchema = (ctor: Function, schema: StructKind) => {
ctor.prototype._borsh_schema = schema;
}
Expand All @@ -324,16 +329,6 @@ export const variant = (index: number | number[]) => {
return (ctor: Function) => {
getOrCreateStructMeta(ctor);

// Define Schema for this class, even though it might miss fields since this is a variant

const clazzes = extendingClasses(ctor);
let prev = ctor;
for (const clazz of clazzes) {
setDependency(clazz, prev); // Super classes are marked so we know they have some importance/meaningfulness
prev = clazz;
}


// Create a custom serialization, for enum by prepend instruction index
ctor.prototype.borshSerialize = function (
writer: BinaryWriter
Expand Down Expand Up @@ -363,6 +358,15 @@ export const variant = (index: number | number[]) => {
ctor.prototype._borsh_variant_index = function () {
return index; // creates a function that returns the variant index on the class
};
// Define Schema for this class, even though it might miss fields since this is a variant
const clazzes = extendingClasses(ctor);
let prev = ctor;
for (const clazz of clazzes) {
setDependency(clazz, prev); // Super classes are marked so we know they have some importance/meaningfulness
prev = clazz;
}


};
};

Expand Down

0 comments on commit ff46fc7

Please sign in to comment.