|
|
@ -20,9 +20,12 @@ |
|
|
|
* Ethereum IDE client. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <QDebug> |
|
|
|
#include <vector> |
|
|
|
#include <QMap> |
|
|
|
#include <QStringList> |
|
|
|
#include <QJsonArray> |
|
|
|
#include <QJsonDocument> |
|
|
|
#include <QJsonObject> |
|
|
|
#include <libethcore/CommonJS.h> |
|
|
|
#include <libsolidity/AST.h> |
|
|
|
#include "QVariableDeclaration.h" |
|
|
@ -39,13 +42,18 @@ bytes ContractCallDataEncoder::encodedData() |
|
|
|
bytes r(m_encodedData); |
|
|
|
size_t headerSize = m_encodedData.size() & ~0x1fUL; //ignore any prefix that is not 32-byte aligned
|
|
|
|
//apply offsets
|
|
|
|
for (auto const& p: m_offsetMap) |
|
|
|
for (auto const& p: m_dynamicOffsetMap) |
|
|
|
{ |
|
|
|
vector_ref<byte> offsetRef(m_dynamicData.data() + p.first, 32); |
|
|
|
toBigEndian(p.second + headerSize, offsetRef); //add header size minus signature hash
|
|
|
|
} |
|
|
|
for (auto const& p: m_staticOffsetMap) |
|
|
|
{ |
|
|
|
vector_ref<byte> offsetRef(r.data() + p.first, 32); |
|
|
|
toBigEndian<size_t, vector_ref<byte>>(p.second + headerSize, offsetRef); //add header size minus signature hash
|
|
|
|
toBigEndian(p.second + headerSize, offsetRef); //add header size minus signature hash
|
|
|
|
} |
|
|
|
|
|
|
|
r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); |
|
|
|
if (m_dynamicData.size() > 0) |
|
|
|
r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); |
|
|
|
return r; |
|
|
|
} |
|
|
|
|
|
|
@ -55,54 +63,69 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) |
|
|
|
m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); |
|
|
|
} |
|
|
|
|
|
|
|
void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) |
|
|
|
void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, SolidityType const& _type, bytes& _content) |
|
|
|
{ |
|
|
|
u256 count = 1; |
|
|
|
QStringList strList; |
|
|
|
if (_type.array) |
|
|
|
size_t offsetStart = _content.size(); |
|
|
|
if (_type.dynamicSize) |
|
|
|
{ |
|
|
|
if (_data.type() == QVariant::String) |
|
|
|
strList = _data.toString().split(",", QString::SkipEmptyParts); //TODO: proper parsing
|
|
|
|
else |
|
|
|
strList = _data.toStringList(); |
|
|
|
count = strList.count(); |
|
|
|
bytes count = bytes(32); |
|
|
|
toBigEndian((u256)_array.size(), count); |
|
|
|
_content += count; //reserved space for count
|
|
|
|
} |
|
|
|
|
|
|
|
int k = 0; |
|
|
|
for (QJsonValue const& c: _array) |
|
|
|
{ |
|
|
|
if (c.isArray()) |
|
|
|
{ |
|
|
|
if (_type.baseType->dynamicSize) |
|
|
|
m_dynamicOffsetMap.push_back(std::make_pair(m_dynamicData.size() + offsetStart + 32 + k * 32, m_dynamicData.size() + _content.size())); |
|
|
|
encodeArray(c.toArray(), *_type.baseType, _content); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// encode single item
|
|
|
|
if (c.isDouble()) |
|
|
|
encodeSingleItem(QString::number(c.toDouble()), _type, _content); |
|
|
|
else if (c.isString()) |
|
|
|
encodeSingleItem(c.toString(), _type, _content); |
|
|
|
} |
|
|
|
k++; |
|
|
|
} |
|
|
|
else |
|
|
|
strList.append(_data.toString()); |
|
|
|
} |
|
|
|
|
|
|
|
if (_type.dynamicSize) |
|
|
|
void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) |
|
|
|
{ |
|
|
|
if (_type.dynamicSize && (_type.type == SolidityType::Type::Bytes || _type.type == SolidityType::Type::String)) |
|
|
|
{ |
|
|
|
bytes empty(32); |
|
|
|
size_t sizePos = m_dynamicData.size(); |
|
|
|
m_dynamicData += empty; //reserve space for count
|
|
|
|
if (_type.type == SolidityType::Type::Bytes) |
|
|
|
count = encodeSingleItem(_data.toString(), _type, m_dynamicData); |
|
|
|
else |
|
|
|
{ |
|
|
|
count = strList.count(); |
|
|
|
for (auto const& item: strList) |
|
|
|
encodeSingleItem(item, _type, m_dynamicData); |
|
|
|
} |
|
|
|
u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData); |
|
|
|
vector_ref<byte> sizeRef(m_dynamicData.data() + sizePos, 32); |
|
|
|
toBigEndian(count, sizeRef); |
|
|
|
m_offsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); |
|
|
|
m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); |
|
|
|
m_encodedData += empty; //reserve space for offset
|
|
|
|
} |
|
|
|
else |
|
|
|
else if (_type.array) |
|
|
|
{ |
|
|
|
if (_type.array) |
|
|
|
count = _type.count; |
|
|
|
int c = static_cast<int>(count); |
|
|
|
if (strList.size() > c) |
|
|
|
strList.erase(strList.begin() + c, strList.end()); |
|
|
|
else |
|
|
|
while (strList.size() < c) |
|
|
|
strList.append(QString()); |
|
|
|
bytes content; |
|
|
|
size_t size = m_encodedData.size(); |
|
|
|
if (_type.dynamicSize) |
|
|
|
{ |
|
|
|
m_encodedData += bytes(32); // reserve space for offset
|
|
|
|
m_staticOffsetMap.push_back(std::make_pair(size, m_dynamicData.size())); |
|
|
|
} |
|
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(_data.toString().toUtf8()); |
|
|
|
encodeArray(jsonDoc.array(), _type, content); |
|
|
|
|
|
|
|
for (auto const& item: strList) |
|
|
|
encodeSingleItem(item, _type, m_encodedData); |
|
|
|
if (!_type.dynamicSize) |
|
|
|
m_encodedData.insert(m_encodedData.end(), content.begin(), content.end()); |
|
|
|
else |
|
|
|
m_dynamicData.insert(m_dynamicData.end(), content.begin(), content.end()); |
|
|
|
} |
|
|
|
else |
|
|
|
encodeSingleItem(_data.toString(), _type, m_encodedData); |
|
|
|
} |
|
|
|
|
|
|
|
unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, SolidityType const& _type, bytes& _dest) |
|
|
@ -207,6 +230,13 @@ QString ContractCallDataEncoder::toString(dev::bytes const& _b) |
|
|
|
return QString::fromStdString(dev::toJS(_b)); |
|
|
|
} |
|
|
|
|
|
|
|
QString ContractCallDataEncoder::toChar(dev::bytes const& _b) |
|
|
|
{ |
|
|
|
QString str; |
|
|
|
asString(_b, str); |
|
|
|
return str; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& _value) |
|
|
|
{ |
|
|
@ -220,6 +250,8 @@ QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& |
|
|
|
return QVariant::fromValue(toString(decodeBool(rawParam))); |
|
|
|
else if (type == QSolidityType::Type::Bytes || type == QSolidityType::Type::Hash) |
|
|
|
return QVariant::fromValue(toString(decodeBytes(rawParam))); |
|
|
|
else if (type == QSolidityType::Type::String) |
|
|
|
return QVariant::fromValue(toChar(decodeBytes(rawParam))); |
|
|
|
else if (type == QSolidityType::Type::Struct) |
|
|
|
return QVariant::fromValue(QString("struct")); //TODO
|
|
|
|
else if (type == QSolidityType::Type::Address) |
|
|
|