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