-
Notifications
You must be signed in to change notification settings - Fork 208
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
3.0.0: Improve object encoding and decoding #862
Changes from 1 commit
d003221
6bdc9ba
6e80bd6
71999a6
6f58347
312fd65
04af841
564c889
6637ead
6235396
1ecb5e2
abcbd9a
d6c4913
54aeb78
3b99c59
3d911fc
65e0724
381347d
7e6ca55
0a493ae
272df51
b11917b
3016e9a
ce0d857
d72e724
b864c24
f79528e
6c90132
8a29264
f67acb6
d11db00
c82a856
86a6e11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a reminder, this file is generated, and its changes are a result of algorand/generator#73 |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,25 @@ | ||
import { | ||
MsgpackEncodable, | ||
MsgpackEncodingData, | ||
JSONEncodable, | ||
JSONEncodingData, | ||
msgpackEncodingDataToJSONEncodingData, | ||
jsonEncodingDataToMsgpackEncodingData, | ||
} from '../../encoding/encoding.js'; | ||
import { Encodable, MsgpackEncodingData } from '../../encoding/encoding.js'; | ||
import { UntypedSchema } from '../../encoding/schema/index.js'; | ||
|
||
export class UntypedValue implements Encodable { | ||
static encodingSchema = new UntypedSchema(); | ||
|
||
export class UntypedValue implements MsgpackEncodable, JSONEncodable { | ||
public readonly data: MsgpackEncodingData; | ||
|
||
constructor(data: MsgpackEncodingData) { | ||
this.data = data; | ||
} | ||
|
||
public msgpackPrepare(): MsgpackEncodingData { | ||
return this.data; | ||
// eslint-disable-next-line class-methods-use-this | ||
public getEncodingSchema(): UntypedSchema { | ||
return UntypedValue.encodingSchema; | ||
} | ||
|
||
public jsonPrepare(): JSONEncodingData { | ||
return msgpackEncodingDataToJSONEncodingData(this.data); | ||
} | ||
|
||
public static fromDecodedMsgpack(data: MsgpackEncodingData): UntypedValue { | ||
return new UntypedValue(data); | ||
public toEncodingData(): MsgpackEncodingData { | ||
return this.data; | ||
} | ||
|
||
public static fromDecodedJSON(data: JSONEncodingData): UntypedValue { | ||
return new UntypedValue(jsonEncodingDataToMsgpackEncodingData(data)); | ||
public static fromEncodingData(data: unknown): UntypedValue { | ||
return new UntypedValue(data as MsgpackEncodingData); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { | ||
Schema, | ||
MsgpackEncodingData, | ||
JSONEncodingData, | ||
msgpackEncodingDataToJSONEncodingData, | ||
jsonEncodingDataToMsgpackEncodingData, | ||
} from '../encoding.js'; | ||
|
||
/* eslint-disable class-methods-use-this */ | ||
|
||
export class UntypedSchema extends Schema { | ||
public defaultValue(): undefined { | ||
return undefined; | ||
} | ||
|
||
public isDefaultValue(data: unknown): boolean { | ||
return data === undefined; | ||
} | ||
|
||
public prepareMsgpack(data: unknown): MsgpackEncodingData { | ||
// Value is already MsgpackEncodingData, since it is returned as such from | ||
// fromPreparedMsgpack and fromPreparedJSON | ||
return data as MsgpackEncodingData; | ||
} | ||
|
||
public fromPreparedMsgpack( | ||
encoded: MsgpackEncodingData | ||
): MsgpackEncodingData { | ||
return encoded; | ||
} | ||
|
||
public prepareJSON(data: unknown): JSONEncodingData { | ||
return msgpackEncodingDataToJSONEncodingData(data as MsgpackEncodingData); | ||
} | ||
|
||
public fromPreparedJSON(encoded: JSONEncodingData): MsgpackEncodingData { | ||
return jsonEncodingDataToMsgpackEncodingData(encoded); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,57 @@ | ||
import { | ||
MsgpackEncodable, | ||
MsgpackEncodingData, | ||
JSONEncodable, | ||
JSONEncodingData, | ||
encodeMsgpack, | ||
decodeMsgpack, | ||
msgpackEncodingDataToJSONEncodingData, | ||
Encodable, | ||
encodeMsgpack2 as encodeMsgpack, | ||
decodeMsgpack2 as decodeMsgpack, | ||
} from './encoding/encoding.js'; | ||
import { Address } from './encoding/address.js'; | ||
import { base64ToBytes } from './encoding/binarydata.js'; | ||
import { Transaction } from './transaction.js'; | ||
import { LogicSig } from './logicsig.js'; | ||
import { | ||
EncodedMultisig, | ||
encodedMultiSigMsgpackPrepare, | ||
encodedMultiSigFromDecodedMsgpack, | ||
encodedMultiSigFromDecodedJSON, | ||
ENCODED_MULTISIG_SCHEMA, | ||
} from './types/transactions/index.js'; | ||
import { | ||
AddressSchema, | ||
FixedLengthByteArraySchema, | ||
NamedMapSchema, | ||
} from './encoding/schema/index.js'; | ||
|
||
export class SignedTransaction implements Encodable { | ||
static encodingSchema = new NamedMapSchema([ | ||
{ | ||
key: 'txn', | ||
valueSchema: Transaction.encodingSchema, | ||
required: true, | ||
omitEmpty: true, | ||
}, | ||
{ | ||
key: 'sig', | ||
valueSchema: new FixedLengthByteArraySchema(64), | ||
required: false, | ||
gmalouf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
omitEmpty: true, | ||
}, | ||
{ | ||
key: 'msig', | ||
valueSchema: ENCODED_MULTISIG_SCHEMA, | ||
required: false, | ||
omitEmpty: true, | ||
}, | ||
{ | ||
key: 'lsig', | ||
valueSchema: LogicSig.encodingSchema, | ||
required: false, | ||
omitEmpty: true, | ||
}, | ||
{ | ||
key: 'sgnr', | ||
valueSchema: new AddressSchema(), | ||
required: false, | ||
omitEmpty: true, | ||
}, | ||
]); | ||
|
||
export class SignedTransaction implements MsgpackEncodable, JSONEncodable { | ||
/** | ||
* The transaction that was signed | ||
*/ | ||
|
@@ -74,57 +107,42 @@ export class SignedTransaction implements MsgpackEncodable, JSONEncodable { | |
} | ||
} | ||
|
||
public msgpackPrepare(): MsgpackEncodingData { | ||
const data: Map<string, MsgpackEncodingData> = new Map([ | ||
['txn', this.txn.msgpackPrepare()], | ||
]); | ||
// eslint-disable-next-line class-methods-use-this | ||
public getEncodingSchema() { | ||
return SignedTransaction.encodingSchema; | ||
} | ||
|
||
public toEncodingData(): Map<string, unknown> { | ||
const data = new Map<string, unknown>([['txn', this.txn.toEncodingData()]]); | ||
if (this.sig) { | ||
data.set('sig', this.sig); | ||
} | ||
if (this.msig) { | ||
data.set('msig', encodedMultiSigMsgpackPrepare(this.msig)); | ||
} | ||
if (this.lsig) { | ||
data.set('lsig', this.lsig.msgpackPrepare()); | ||
data.set('lsig', this.lsig.toEncodingData()); | ||
} | ||
if (this.sgnr) { | ||
data.set('sgnr', this.sgnr.publicKey); | ||
data.set('sgnr', this.sgnr); | ||
} | ||
return data; | ||
} | ||
|
||
public static fromDecodedMsgpack(data: unknown): SignedTransaction { | ||
public static fromEncodingData(data: unknown): SignedTransaction { | ||
if (!(data instanceof Map)) { | ||
throw new Error(`Invalid decoded SignedTransaction: ${data}`); | ||
} | ||
return new SignedTransaction({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should there be a check for more than one signature on decode? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not so sure about this. If you try to create a signed txn with more than one signature, then yes we should error and stop you because you're doing something wrong and it's best to fail early. But if you're just trying to read such a transaction that someone else created, I don't see a clear benefit to erroring in that case. There are almost an unlimited number of ways you can invalidate a transaction, and I'm not sure it's worth the effort to try to validate every field completely upon decoding (we do validate that field types are correct, but field values/consistency is another thing entirely). That will be done when you send the transaction to a node for processing anyway. |
||
txn: Transaction.fromDecodedMsgpack(data.get('txn')), | ||
txn: Transaction.fromEncodingData(data.get('txn')), | ||
sig: data.get('sig'), | ||
msig: data.get('msig') | ||
? encodedMultiSigFromDecodedMsgpack(data.get('msig')) | ||
: undefined, | ||
lsig: data.get('lsig') | ||
? LogicSig.fromDecodedMsgpack(data.get('lsig')) | ||
? LogicSig.fromEncodingData(data.get('lsig')) | ||
: undefined, | ||
sgnr: data.get('sgnr') ? new Address(data.get('sgnr')) : undefined, | ||
}); | ||
} | ||
|
||
public jsonPrepare(): JSONEncodingData { | ||
return msgpackEncodingDataToJSONEncodingData(this.msgpackPrepare()); | ||
} | ||
|
||
public static fromDecodedJSON(data: unknown): SignedTransaction { | ||
if (data === null || typeof data !== 'object') { | ||
throw new Error(`Invalid decoded SignedTransaction: ${data}`); | ||
} | ||
const obj = data as Record<string, any>; | ||
return new SignedTransaction({ | ||
txn: Transaction.fromDecodedJSON(obj.txn), | ||
sig: obj.sig ? base64ToBytes(obj.sig) : undefined, | ||
msig: obj.msig ? encodedMultiSigFromDecodedJSON(obj.msig) : undefined, | ||
lsig: obj.lsig ? LogicSig.fromDecodedJSON(obj.lsig) : undefined, | ||
sgnr: obj.sgnr ? Address.fromString(obj.sgnr) : undefined, | ||
sgnr: data.get('sgnr'), | ||
}); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a reminder, this file is generated, and its changes are a result of algorand/generator#73