-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feat/next' into duplicate-local-tests
- Loading branch information
Showing
38 changed files
with
1,777 additions
and
1,457 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export class TypeFormula { | ||
name: string; | ||
typeParameters: TypeFormula[]; | ||
|
||
constructor(name: string, typeParameters: TypeFormula[]) { | ||
this.name = name; | ||
this.typeParameters = typeParameters; | ||
} | ||
|
||
toString(): string { | ||
if (this.typeParameters.length > 0) { | ||
const typeParameters = this.typeParameters.map((typeParameter) => typeParameter.toString()).join(", "); | ||
return `${this.name}<${typeParameters}>`; | ||
} else { | ||
return this.name; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { assert } from "chai"; | ||
import { TypeFormulaParser } from "./typeFormulaParser"; | ||
|
||
describe("test type formula parser", () => { | ||
it("should parse expression", async () => { | ||
const parser = new TypeFormulaParser(); | ||
|
||
const testVectors = [ | ||
["i64", "i64"], | ||
[" i64 ", "i64"], | ||
["utf-8 string", "utf-8 string"], | ||
["MultiResultVec<MultiResult2<Address, u64>>", "MultiResultVec<MultiResult2<Address, u64>>"], | ||
["tuple3<i32, bytes, Option<i64>>", "tuple3<i32, bytes, Option<i64>>"], | ||
["tuple2<i32, i32>", "tuple2<i32, i32>"], | ||
["tuple2<i32,i32> ", "tuple2<i32, i32>"], | ||
["tuple<List<u64>, List<u64>>", "tuple<List<u64>, List<u64>>"], | ||
]; | ||
|
||
for (const [inputExpression, expectedExpression] of testVectors) { | ||
const typeFormula = parser.parseExpression(inputExpression); | ||
const outputExpression = typeFormula.toString(); | ||
assert.equal(outputExpression, expectedExpression); | ||
} | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { TypeFormula } from "./typeFormula"; | ||
|
||
export class TypeFormulaParser { | ||
static BEGIN_TYPE_PARAMETERS = "<"; | ||
static END_TYPE_PARAMETERS = ">"; | ||
static COMMA = ","; | ||
static PUNCTUATION = [ | ||
TypeFormulaParser.COMMA, | ||
TypeFormulaParser.BEGIN_TYPE_PARAMETERS, | ||
TypeFormulaParser.END_TYPE_PARAMETERS, | ||
]; | ||
|
||
parseExpression(expression: string): TypeFormula { | ||
expression = expression.trim(); | ||
|
||
const tokens = this.tokenizeExpression(expression).filter((token) => token !== TypeFormulaParser.COMMA); | ||
const stack: any[] = []; | ||
|
||
for (const token of tokens) { | ||
if (this.isPunctuation(token)) { | ||
if (this.isEndOfTypeParameters(token)) { | ||
const typeFormula = this.acquireTypeWithParameters(stack); | ||
stack.push(typeFormula); | ||
} else if (this.isBeginningOfTypeParameters(token)) { | ||
// This symbol is pushed as a simple string. | ||
stack.push(token); | ||
} else { | ||
throw new Error(`Unexpected token (punctuation): ${token}`); | ||
} | ||
} else { | ||
// It's a type name. We push it as a simple string. | ||
stack.push(token); | ||
} | ||
} | ||
|
||
if (stack.length !== 1) { | ||
throw new Error(`Unexpected stack length at end of parsing: ${stack.length}`); | ||
} | ||
if (TypeFormulaParser.PUNCTUATION.includes(stack[0])) { | ||
throw new Error("Unexpected root element."); | ||
} | ||
|
||
const item = stack[0]; | ||
|
||
if (item instanceof TypeFormula) { | ||
return item; | ||
} else if (typeof item === "string") { | ||
// Expression contained a simple, non-generic type. | ||
return new TypeFormula(item, []); | ||
} else { | ||
throw new Error(`Unexpected item on stack: ${item}`); | ||
} | ||
} | ||
|
||
private tokenizeExpression(expression: string): string[] { | ||
const tokens: string[] = []; | ||
let currentToken = ""; | ||
|
||
for (const character of expression) { | ||
if (this.isPunctuation(character)) { | ||
if (currentToken) { | ||
// Retain current token | ||
tokens.push(currentToken.trim()); | ||
// Reset current token | ||
currentToken = ""; | ||
} | ||
|
||
// Punctuation character | ||
tokens.push(character); | ||
} else { | ||
currentToken += character; | ||
} | ||
} | ||
|
||
if (currentToken) { | ||
// Retain the last token (if any). | ||
tokens.push(currentToken.trim()); | ||
} | ||
|
||
return tokens; | ||
} | ||
|
||
private acquireTypeWithParameters(stack: any[]): TypeFormula { | ||
const typeParameters = this.acquireTypeParameters(stack); | ||
const typeName = stack.pop(); | ||
const typeFormula = new TypeFormula(typeName, typeParameters.reverse()); | ||
return typeFormula; | ||
} | ||
|
||
private acquireTypeParameters(stack: any[]): TypeFormula[] { | ||
const typeParameters: TypeFormula[] = []; | ||
|
||
while (true) { | ||
const item = stack.pop(); | ||
|
||
if (item === undefined) { | ||
throw new Error("Badly specified type parameters"); | ||
} | ||
|
||
if (this.isBeginningOfTypeParameters(item)) { | ||
// We've acquired all type parameters. | ||
break; | ||
} | ||
|
||
if (item instanceof TypeFormula) { | ||
// Type parameter is a previously-acquired type. | ||
typeParameters.push(item); | ||
} else if (typeof item === "string") { | ||
// Type parameter is a simple, non-generic type. | ||
typeParameters.push(new TypeFormula(item, [])); | ||
} else { | ||
throw new Error(`Unexpected type parameter object in stack: ${item}`); | ||
} | ||
} | ||
|
||
return typeParameters; | ||
} | ||
|
||
private isPunctuation(token: string): boolean { | ||
return TypeFormulaParser.PUNCTUATION.includes(token); | ||
} | ||
|
||
private isEndOfTypeParameters(token: string): boolean { | ||
return token === TypeFormulaParser.END_TYPE_PARAMETERS; | ||
} | ||
|
||
private isBeginningOfTypeParameters(token: string): boolean { | ||
return token === TypeFormulaParser.BEGIN_TYPE_PARAMETERS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { TransactionsConverter } from "./transactionsConverter"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { IPlainTransactionObject, ITransaction } from "../interface"; | ||
import { Transaction } from "../transaction"; | ||
|
||
export class TransactionsConverter { | ||
public transactionToPlainObject(transaction: ITransaction): IPlainTransactionObject { | ||
const plainObject = { | ||
nonce: Number(transaction.nonce), | ||
value: transaction.value.toString(), | ||
receiver: transaction.receiver, | ||
sender: transaction.sender, | ||
senderUsername: this.toBase64OrUndefined(transaction.senderUsername), | ||
receiverUsername: this.toBase64OrUndefined(transaction.receiverUsername), | ||
gasPrice: Number(transaction.gasPrice), | ||
gasLimit: Number(transaction.gasLimit), | ||
data: this.toBase64OrUndefined(transaction.data), | ||
chainID: transaction.chainID.valueOf(), | ||
version: transaction.version, | ||
options: transaction.options == 0 ? undefined : transaction.options, | ||
guardian: transaction.guardian ? transaction.guardian : undefined, | ||
signature: this.toHexOrUndefined(transaction.signature), | ||
guardianSignature: this.toHexOrUndefined(transaction.guardianSignature), | ||
}; | ||
|
||
return plainObject; | ||
} | ||
|
||
private toBase64OrUndefined(value?: string | Uint8Array) { | ||
return value && value.length ? Buffer.from(value).toString("base64") : undefined; | ||
} | ||
|
||
private toHexOrUndefined(value?: Uint8Array) { | ||
return value && value.length ? Buffer.from(value).toString("hex") : undefined; | ||
} | ||
|
||
public plainObjectToTransaction(object: IPlainTransactionObject): Transaction { | ||
const transaction = new Transaction({ | ||
nonce: BigInt(object.nonce), | ||
value: BigInt(object.value || ""), | ||
receiver: object.receiver, | ||
receiverUsername: this.bufferFromBase64(object.receiverUsername).toString(), | ||
sender: object.sender, | ||
senderUsername: this.bufferFromBase64(object.senderUsername).toString(), | ||
guardian: object.guardian, | ||
gasPrice: BigInt(object.gasPrice), | ||
gasLimit: BigInt(object.gasLimit), | ||
data: this.bufferFromBase64(object.data), | ||
chainID: String(object.chainID), | ||
version: object.version, | ||
options: object.options, | ||
signature: this.bufferFromHex(object.signature), | ||
guardianSignature: this.bufferFromHex(object.guardianSignature), | ||
}); | ||
|
||
return transaction; | ||
} | ||
|
||
private bufferFromBase64(value?: string) { | ||
return Buffer.from(value || "", "base64"); | ||
} | ||
|
||
private bufferFromHex(value?: string) { | ||
return Buffer.from(value || "", "hex"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { assert } from "chai"; | ||
import { Transaction } from "../transaction"; | ||
|
||
describe("test transactions converter", async () => { | ||
it("converts transaction to plain object and back", () => { | ||
const transaction = new Transaction({ | ||
nonce: 90, | ||
value: BigInt("123456789000000000000000000000"), | ||
sender: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", | ||
receiver: "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", | ||
senderUsername: "alice", | ||
receiverUsername: "bob", | ||
gasPrice: 1000000000, | ||
gasLimit: 80000, | ||
data: Buffer.from("hello"), | ||
chainID: "localnet", | ||
}); | ||
|
||
const plainObject = transaction.toPlainObject(); | ||
const restoredTransaction = Transaction.fromPlainObject(plainObject); | ||
assert.deepEqual(restoredTransaction, transaction); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.