@truffle/codec
Version:
Library for encoding and decoding smart contract data
266 lines • 9.93 kB
JavaScript
/**
* @protected
*
* @packageDocumentation
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeMemoryReferenceByAddress = exports.decodeMemory = void 0;
const debug_1 = __importDefault(require("debug"));
const debug = (0, debug_1.default)("codec:memory:decode");
const read_1 = __importDefault(require("../../read"));
const Conversion = __importStar(require("../../conversion"));
const Format = __importStar(require("../../format"));
const Basic = __importStar(require("../../basic"));
const Bytes = __importStar(require("../../bytes"));
const Evm = __importStar(require("../../evm"));
const allocate_1 = require("../allocate");
const errors_1 = require("../../errors");
function* decodeMemory(dataType, pointer, info, options = {}) {
if (Format.Types.isReferenceType(dataType)) {
if ((0, allocate_1.isSkippedInMemoryStructs)(dataType)) {
//special case; these types are always empty in memory
return decodeMemorySkippedType(dataType);
}
else {
return yield* decodeMemoryReferenceByAddress(dataType, pointer, info, options);
}
}
else {
return yield* Basic.Decode.decodeBasic(dataType, pointer, info, options);
}
}
exports.decodeMemory = decodeMemory;
function decodeMemorySkippedType(dataType) {
switch (dataType.typeClass) {
case "mapping":
return {
type: dataType,
kind: "value",
value: [],
interpretations: {}
};
case "array":
return {
type: dataType,
kind: "value",
value: [],
interpretations: {}
};
//other cases should not arise!
}
}
function* decodeMemoryReferenceByAddress(dataType, pointer, info, options = {}) {
const { state } = info;
const memoryVisited = options.memoryVisited || [];
debug("pointer %o", pointer);
let rawValue;
try {
rawValue = yield* (0, read_1.default)(pointer, state);
}
catch (error) {
return (0, errors_1.handleDecodingError)(dataType, error);
}
let startPositionAsBN = Conversion.toBN(rawValue);
let startPosition;
try {
startPosition = startPositionAsBN.toNumber();
}
catch (_a) {
return {
//again with the TS failures...
type: dataType,
kind: "error",
error: {
kind: "OverlargePointersNotImplementedError",
pointerAsBN: startPositionAsBN
}
};
}
//startPosition may get modified later, so let's save the current
//value for circularity detection purposes
const objectPosition = startPosition;
let rawLength;
let lengthAsBN;
let length;
let seenPreviously;
switch (dataType.typeClass) {
case "bytes":
case "string":
//initial word contains length
try {
rawLength = yield* (0, read_1.default)({
location: "memory",
start: startPosition,
length: Evm.Utils.WORD_SIZE
}, state);
}
catch (error) {
return (0, errors_1.handleDecodingError)(dataType, error);
}
lengthAsBN = Conversion.toBN(rawLength);
try {
length = lengthAsBN.toNumber();
}
catch (_b) {
return {
//again with the TS failures...
type: dataType,
kind: "error",
error: {
kind: "OverlongArraysAndStringsNotImplementedError",
lengthAsBN
}
};
}
let childPointer = {
location: "memory",
start: startPosition + Evm.Utils.WORD_SIZE,
length
};
return yield* Bytes.Decode.decodeBytes(dataType, childPointer, info);
case "array": {
//first: circularity check!
seenPreviously = memoryVisited.indexOf(objectPosition);
if (seenPreviously !== -1) {
return {
type: dataType,
kind: "value",
reference: seenPreviously + 1,
value: [],
interpretations: {}
};
}
//otherwise, decode as normal
if (dataType.kind === "dynamic") {
//initial word contains array length
try {
rawLength = yield* (0, read_1.default)({
location: "memory",
start: startPosition,
length: Evm.Utils.WORD_SIZE
}, state);
}
catch (error) {
return (0, errors_1.handleDecodingError)(dataType, error);
}
lengthAsBN = Conversion.toBN(rawLength);
startPosition += Evm.Utils.WORD_SIZE; //increment startPosition
//to next word, as first word was used for length
}
else {
lengthAsBN = dataType.length;
}
try {
length = lengthAsBN.toNumber();
}
catch (_c) {
return {
type: dataType,
kind: "error",
error: {
kind: "OverlongArraysAndStringsNotImplementedError",
lengthAsBN
}
};
}
let memoryNowVisited = [objectPosition, ...memoryVisited];
let baseType = dataType.baseType;
let decodedChildren = [];
for (let index = 0; index < length; index++) {
decodedChildren.push(yield* decodeMemory(baseType, {
location: "memory",
start: startPosition + index * Evm.Utils.WORD_SIZE,
length: Evm.Utils.WORD_SIZE
}, info, { memoryVisited: memoryNowVisited }));
}
return {
type: dataType,
kind: "value",
value: decodedChildren,
interpretations: {}
};
}
case "struct": {
//first: circularity check!
seenPreviously = memoryVisited.indexOf(objectPosition);
if (seenPreviously !== -1) {
return {
type: dataType,
kind: "value",
reference: seenPreviously + 1,
value: [],
interpretations: {}
};
}
//otherwise, decode as normal
const { allocations: { memory: allocations } } = info;
const typeId = dataType.id;
const structAllocation = allocations[typeId];
if (!structAllocation) {
return {
type: dataType,
kind: "error",
error: {
kind: "UserDefinedTypeNotFoundError",
type: dataType
}
};
}
debug("structAllocation %O", structAllocation);
let memoryNowVisited = [objectPosition, ...memoryVisited];
let decodedMembers = [];
for (let index = 0; index < structAllocation.members.length; index++) {
const memberAllocation = structAllocation.members[index];
const memberPointer = memberAllocation.pointer;
const childPointer = {
location: "memory",
start: startPosition + memberPointer.start,
length: memberPointer.length //always equals WORD_SIZE or 0
};
let memberName = memberAllocation.name;
let memberType = Format.Types.specifyLocation(memberAllocation.type, "memory");
decodedMembers.push({
name: memberName,
value: yield* decodeMemory(memberType, childPointer, info, {
memoryVisited: memoryNowVisited
})
});
}
return {
type: dataType,
kind: "value",
value: decodedMembers,
interpretations: {}
};
}
}
}
exports.decodeMemoryReferenceByAddress = decodeMemoryReferenceByAddress;
//# sourceMappingURL=index.js.map
;