Comments and inline documentation for dynamic bytes
This commit is contained in:
@@ -22,10 +22,6 @@ export class Bool extends PayloadDataType {
|
||||
}
|
||||
}
|
||||
|
||||
public getSignature(): string {
|
||||
return 'bool';
|
||||
}
|
||||
|
||||
public encodeValue(value: boolean): Buffer {
|
||||
const encodedValue = value ? '0x1' : '0x0';
|
||||
const encodedValueBuf = ethUtil.setLengthLeft(
|
||||
@@ -47,4 +43,8 @@ export class Bool extends PayloadDataType {
|
||||
/* tslint:enable boolean-naming */
|
||||
return value;
|
||||
}
|
||||
|
||||
public getSignature(): string {
|
||||
return 'bool';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,42 +17,53 @@ export class DynamicBytes extends PayloadDataType {
|
||||
public constructor(dataItem: DataItem, dataTypeFactory: DataTypeFactory) {
|
||||
super(dataItem, dataTypeFactory, DynamicBytes._SIZE_KNOWN_AT_COMPILE_TIME);
|
||||
if (!DynamicBytes.matchType(dataItem.type)) {
|
||||
throw new Error(`Tried to instantiate DynamicBytes with bad input: ${dataItem}`);
|
||||
throw new Error(`Tried to instantiate Dynamic Bytes with bad input: ${dataItem}`);
|
||||
}
|
||||
}
|
||||
|
||||
public encodeValue(value: string | Buffer): Buffer {
|
||||
if (typeof value === 'string' && !value.startsWith('0x')) {
|
||||
throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '${value}'`);
|
||||
}
|
||||
// Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
|
||||
// 1/3 Construct the length
|
||||
const valueBuf = ethUtil.toBuffer(value);
|
||||
if (value.length % 2 !== 0) {
|
||||
throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
|
||||
}
|
||||
|
||||
const wordsForValue = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
|
||||
const paddedDynamicBytesForValue = wordsForValue * Constants.EVM_WORD_WIDTH_IN_BYTES;
|
||||
const paddedValueBuf = ethUtil.setLengthRight(valueBuf, paddedDynamicBytesForValue);
|
||||
const paddedLengthBuf = ethUtil.setLengthLeft(
|
||||
ethUtil.toBuffer(valueBuf.byteLength),
|
||||
Constants.EVM_WORD_WIDTH_IN_BYTES,
|
||||
);
|
||||
const encodedValueBuf = Buffer.concat([paddedLengthBuf, paddedValueBuf]);
|
||||
return encodedValueBuf;
|
||||
const wordsToStoreValuePadded = Math.ceil(valueBuf.byteLength / Constants.EVM_WORD_WIDTH_IN_BYTES);
|
||||
const bytesToStoreValuePadded = wordsToStoreValuePadded * Constants.EVM_WORD_WIDTH_IN_BYTES;
|
||||
const lengthBuf = ethUtil.toBuffer(valueBuf.byteLength);
|
||||
const lengthBufPadded = ethUtil.setLengthLeft(lengthBuf, Constants.EVM_WORD_WIDTH_IN_BYTES);
|
||||
// 2/3 Construct the value
|
||||
this._sanityCheckValue(value);
|
||||
const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
|
||||
// 3/3 Combine length and value
|
||||
const encodedValue = Buffer.concat([lengthBufPadded, valueBufPadded]);
|
||||
return encodedValue;
|
||||
}
|
||||
|
||||
public decodeValue(calldata: RawCalldata): string {
|
||||
// Encoded value is of the form: <length><value>, with each field padded to be word-aligned.
|
||||
// 1/2 Decode length
|
||||
const lengthBuf = calldata.popWord();
|
||||
const lengthHex = ethUtil.bufferToHex(lengthBuf);
|
||||
const length = parseInt(lengthHex, Constants.HEX_BASE);
|
||||
const wordsForValue = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
|
||||
const paddedValueBuf = calldata.popWords(wordsForValue);
|
||||
const valueBuf = paddedValueBuf.slice(0, length);
|
||||
const decodedValue = ethUtil.bufferToHex(valueBuf);
|
||||
return decodedValue;
|
||||
// 2/2 Decode value
|
||||
const wordsToStoreValuePadded = Math.ceil(length / Constants.EVM_WORD_WIDTH_IN_BYTES);
|
||||
const valueBufPadded = calldata.popWords(wordsToStoreValuePadded);
|
||||
const valueBuf = valueBufPadded.slice(0, length);
|
||||
const value = ethUtil.bufferToHex(valueBuf);
|
||||
this._sanityCheckValue(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public getSignature(): string {
|
||||
return 'bytes';
|
||||
}
|
||||
|
||||
private _sanityCheckValue(value: string | Buffer): void {
|
||||
if (typeof value !== 'string') {
|
||||
return;
|
||||
}
|
||||
if (!value.startsWith('0x')) {
|
||||
throw new Error(`Tried to encode non-hex value. Value must inlcude '0x' prefix.`);
|
||||
} else if (value.length % 2 !== 0) {
|
||||
throw new Error(`Tried to assign ${value}, which is contains a half-byte. Use full bytes only.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ export class String extends PayloadDataType {
|
||||
const valueBuf = new Buffer(value);
|
||||
const valueBufPadded = ethUtil.setLengthRight(valueBuf, bytesToStoreValuePadded);
|
||||
// 3/3 Combine length and value
|
||||
const encodedValueBuf = Buffer.concat([lengthBufPadded, valueBufPadded]);
|
||||
return encodedValueBuf;
|
||||
const encodedValue = Buffer.concat([lengthBufPadded, valueBufPadded]);
|
||||
return encodedValue;
|
||||
}
|
||||
|
||||
public decodeValue(calldata: RawCalldata): string {
|
||||
|
||||
@@ -1018,7 +1018,7 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => {
|
||||
// Encode Args and validate result
|
||||
expect(() => {
|
||||
dataType.encode(args);
|
||||
}).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix. Got '01'");
|
||||
}).to.throw("Tried to encode non-hex value. Value must inlcude '0x' prefix.");
|
||||
});
|
||||
it('Should throw when pass in bad hex (include a half-byte)', async () => {
|
||||
// Create DataType object
|
||||
|
||||
Reference in New Issue
Block a user