Allow events to use compact bytes ABI coded data for Solidity 0.4 external events (#891, #992).

This commit is contained in:
Richard Moore 2020-09-07 19:35:37 -04:00
parent 97acaa1129
commit 4e394fc680
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
5 changed files with 21 additions and 23 deletions

@ -83,8 +83,8 @@ export class AbiCoder {
_getWordSize(): number { return 32; }
_getReader(data: Uint8Array): Reader {
return new Reader(data, this._getWordSize(), this.coerceFunc);
_getReader(data: Uint8Array, allowLoose?: boolean): Reader {
return new Reader(data, this._getWordSize(), this.coerceFunc, allowLoose);
}
_getWriter(): Writer {
@ -107,10 +107,10 @@ export class AbiCoder {
return writer.data;
}
decode(types: Array<string | ParamType>, data: BytesLike): Result {
decode(types: Array<string | ParamType>, data: BytesLike, loose?: boolean): Result {
const coders: Array<Coder> = types.map((type) => this._getCoder(ParamType.from(type)));
const coder = new TupleCoder(coders, "_");
return coder.decode(this._getReader(arrayify(data)));
return coder.decode(this._getReader(arrayify(data), loose));
}
}

@ -131,16 +131,18 @@ export class Writer {
export class Reader {
readonly wordSize: number;
readonly allowLoose: boolean;
readonly _data: Uint8Array;
readonly _coerceFunc: CoerceFunc;
_offset: number;
constructor(data: BytesLike, wordSize?: number, coerceFunc?: CoerceFunc) {
constructor(data: BytesLike, wordSize?: number, coerceFunc?: CoerceFunc, allowLoose?: boolean) {
defineReadOnly(this, "_data", arrayify(data));
defineReadOnly(this, "wordSize", wordSize || 32);
defineReadOnly(this, "_coerceFunc", coerceFunc);
defineReadOnly(this, "allowLoose", allowLoose);
this._offset = 0;
}
@ -160,23 +162,27 @@ export class Reader {
return Reader.coerce(name, value);
}
_peekBytes(offset: number, length: number): Uint8Array {
_peekBytes(offset: number, length: number, loose?: boolean): Uint8Array {
let alignedLength = Math.ceil(length / this.wordSize) * this.wordSize;
if (this._offset + alignedLength > this._data.length) {
if (this.allowLoose && loose && this._offset + length <= this._data.length) {
alignedLength = length;
} else {
logger.throwError("data out-of-bounds", Logger.errors.BUFFER_OVERRUN, {
length: this._data.length,
offset: this._offset + alignedLength
});
}
}
return this._data.slice(this._offset, this._offset + alignedLength)
}
subReader(offset: number): Reader {
return new Reader(this._data.slice(this._offset + offset), this.wordSize, this._coerceFunc);
return new Reader(this._data.slice(this._offset + offset), this.wordSize, this._coerceFunc, this.allowLoose);
}
readBytes(length: number): Uint8Array {
let bytes = this._peekBytes(0, length);
readBytes(length: number, loose?: boolean): Uint8Array {
let bytes = this._peekBytes(0, length, !!loose);
this._offset += bytes.length;
// @TODO: Make sure the length..end bytes are all 0?
return bytes.slice(0, length);

@ -86,9 +86,6 @@ export function unpack(reader: Reader, coders: Array<Coder>): Result {
// A reader anchored to this base
let baseReader = reader.subReader(0);
// The amount of dynamic data read; to consume later to synchronize
let dynamicLength = 0;
coders.forEach((coder) => {
let value: any = null;
@ -105,7 +102,6 @@ export function unpack(reader: Reader, coders: Array<Coder>): Result {
value.name = coder.localName;
value.type = coder.type;
}
dynamicLength += offsetReader.consumed;
} else {
try {
@ -125,10 +121,6 @@ export function unpack(reader: Reader, coders: Array<Coder>): Result {
}
});
// @TODO: get rid of this an see if it still works?
// Consume the dynamic components in the main reader
reader.readBytes(dynamicLength);
// We only output named properties for uniquely named coders
const uniqueNames = coders.reduce((accum, coder) => {
const name = coder.localName;

@ -17,7 +17,7 @@ export class DynamicBytesCoder extends Coder {
}
decode(reader: Reader): any {
return reader.readBytes(reader.readValue().toNumber());
return reader.readBytes(reader.readValue().toNumber(), true);
}
}

@ -475,7 +475,7 @@ export class Interface {
});
let resultIndexed = (topics != null) ? this._abiCoder.decode(indexed, concat(topics)): null;
let resultNonIndexed = this._abiCoder.decode(nonIndexed, data);
let resultNonIndexed = this._abiCoder.decode(nonIndexed, data, true);
let result: (Array<any> & { [ key: string ]: any }) = [ ];
let nonIndexedIndex = 0, indexedIndex = 0;