Browse Source

Merge pull request #2206 from yann300/bugFix

Mix - bug fixes
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
058d557fc7
  1. 12
      mix/CodeModel.cpp
  2. 2
      mix/CodeModel.h
  3. 102
      mix/ContractCallDataEncoder.cpp
  4. 5
      mix/ContractCallDataEncoder.h
  5. 1
      mix/QVariableDeclaration.h
  6. 1
      mix/SolidityType.h
  7. 3
      mix/qml/QIntTypeView.qml
  8. 22
      mix/qml/QStringTypeView.qml
  9. 2
      mix/qml/StructView.qml
  10. 107
      mix/qml/js/InputValidator.js
  11. 3
      mix/qml/js/ProjectModel.js

12
mix/CodeModel.cpp

@ -493,9 +493,18 @@ dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, co
return m_compiledContracts.at(_contractName);
}
void CodeModel::retrieveSubType(SolidityType& _wrapperType, dev::solidity::Type const* _type)
{
if (_type->getCategory() == Type::Category::Array)
{
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(_type);
_wrapperType.baseType = std::make_shared<dev::mix::SolidityType const>(nodeType(arrayType->getBaseType().get()));
}
}
SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
{
SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString()), std::vector<SolidityDeclaration>(), std::vector<QString>() };
SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString()), std::vector<SolidityDeclaration>(), std::vector<QString>(), nullptr };
if (!_type)
return r;
switch (_type->getCategory())
@ -536,6 +545,7 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
r.count = static_cast<unsigned>(array->getLength());
r.dynamicSize = _type->isDynamicallySized();
r.array = true;
retrieveSubType(r, _type);
}
break;
case Type::Category::Enum:

2
mix/CodeModel.h

@ -224,6 +224,8 @@ public:
Q_INVOKABLE void unregisterContractSrc(QString const& _documentId);
/// Convert solidity type info to mix type
static SolidityType nodeType(dev::solidity::Type const* _type);
/// Retrieve subtype
static void retrieveSubType(SolidityType& _wrapperType, dev::solidity::Type const* _type);
/// Check if given location belongs to contract or function
bool isContractOrFunctionLocation(dev::SourceLocation const& _location);
/// Get funciton name by location

102
mix/ContractCallDataEncoder.cpp

@ -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,12 +42,17 @@ 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
}
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
strList.append(_data.toString());
{
// encode single item
if (c.isDouble())
encodeSingleItem(QString::number(c.toDouble()), _type, _content);
else if (c.isString())
encodeSingleItem(c.toString(), _type, _content);
}
k++;
}
}
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)

5
mix/ContractCallDataEncoder.h

@ -71,11 +71,14 @@ private:
QString toString(bool _b);
QString toString(dev::bytes const& _b);
bool asString(dev::bytes const& _b, QString& _str);
void encodeArray(QJsonArray const& _array, SolidityType const& _type, bytes& _content);
QString toChar(dev::bytes const& _b);
private:
bytes m_encodedData;
bytes m_dynamicData;
std::vector<std::pair<size_t, size_t>> m_offsetMap;
std::vector<std::pair<size_t, size_t>> m_dynamicOffsetMap;
std::vector<std::pair<size_t, size_t>> m_staticOffsetMap;
};
}

1
mix/QVariableDeclaration.h

@ -60,6 +60,7 @@ public:
Bool,
Address,
Bytes,
String,
Enum,
Struct
};

1
mix/SolidityType.h

@ -57,6 +57,7 @@ struct SolidityType
QString name;
std::vector<SolidityDeclaration> members; //for struct
std::vector<QString> enumNames; //for enum
std::shared_ptr<SolidityType const> baseType;
};
struct SolidityDeclaration

3
mix/qml/QIntTypeView.qml

@ -33,6 +33,3 @@ Item
}
}
}

22
mix/qml/QStringTypeView.qml

@ -5,25 +5,31 @@ Item
property alias value: textinput.text
property alias readOnly: textinput.readOnly
id: editRoot
height: 20
width: readOnly ? textinput.implicitWidth : 150
SourceSansProBold
{
id: boldFont
DebuggerPaneStyle {
id: dbgStyle
}
Rectangle {
anchors.fill: parent
radius: 4
TextInput {
anchors.verticalCenter: parent.verticalCenter
id: textinput
text: value
font.family: dbgStyle.general.basicFont
clip: true
anchors.fill: parent
wrapMode: Text.WrapAnywhere
font.family: boldFont.name
selectByMouse: true
text: value
anchors.fill: parent
font.pointSize: dbgStyle.general.basicFontSize
color: dbgStyle.general.basicColor
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

2
mix/qml/StructView.qml

@ -72,7 +72,7 @@ Column
return Qt.createComponent("qrc:/qml/QIntTypeView.qml");
else if (t === QSolidityType.Bool)
return Qt.createComponent("qrc:/qml/QBoolTypeView.qml");
else if (t === QSolidityType.Bytes)
else if (t === QSolidityType.Bytes || t === QSolidityType.String)
return Qt.createComponent("qrc:/qml/QStringTypeView.qml");
else if (t === QSolidityType.Hash)
return Qt.createComponent("qrc:/qml/QHashTypeView.qml");

107
mix/qml/js/InputValidator.js

@ -1,32 +1,115 @@
Qt.include("QEtherHelper.js")
var nbRegEx = new RegExp('^[0-9]+$');
var nbRegEx;
var arrayRegEx;
var capturenbRegEx;
function validate(model, values)
{
var inError = [];
for (var k in model)
{
init()
if (values[model[k].name])
{
var type = model[k].type.name;
var res;
var value = values[model[k].name];
var res = check(type, value)
if (!res.valid)
inError.push({ type: type, value: values, message: res.message });
}
}
return inError;
}
function init()
{
nbRegEx = new RegExp('^[0-9]+$');
arrayRegEx = new RegExp('\\[[^\\]]*\\]', "g");
capturenbRegEx = new RegExp("[0-9]+");
}
function check(type, value)
{
var res = { valid: true, message : "" }
if (isContractType(type))
res = validateAddress(type, values[model[k].name]);
res = validateAddress(type, value);
else if (isArray(type))
res = validateArray(type, value);
else if (type.indexOf("int") !== -1)
res = validateInt(type, values[model[k].name]);
res = validateInt(type, value);
else if (type.indexOf("bytes") !== -1)
res = validateBytes(type, values[model[k].name]);
res = validateBytes(type, value);
else if (type.indexOf("bool") !== -1)
res = validateBool(type, values[model[k].name]);
res = validateBool(type, value);
else if (type.indexOf("address") !== -1)
res = validateAddress(type, values[model[k].name]);
res = validateAddress(type, value);
else
res.valid = true;
if (!res.valid)
inError.push({ type: type, value: values, message: res.message });
{
res.valid = true
res.message = ""
}
return res;
}
function isArray(_type)
{
return arrayRegEx.test(_type);
}
function checkArrayRecursively(_type, _dim, _array)
{
if (_array instanceof Array)
{
if (_dim.length === 0)
return { valid: false, message: "Your input contains too many dimensions" }
var size = -1
var infinite = false
if (_dim === "[]")
infinite = true
else
size = parseInt(capturenbRegEx.exec(_dim[0]))
if (_array.length > size && !infinite)
return { valid: false, message: "Array size does not correspond. Should be " + _dim[0] }
if (_array.length > 0)
{
var _newdim = _dim.slice(0)
_newdim.splice(0, 1)
for (var i = 0; i < _array.length; i++)
{
var ret = checkArrayRecursively(_type, _newdim, _array[i])
if (!ret.valid)
return ret
}
return inError;
}
return { valid: true, message: "" }
}
else
{
if (_dim.length > 0)
return { valid: false, message: "Your input contains too few dimensions" }
if (typeof(_array) === "number")
_array = '' + _array + ''
return check(_type, _array)
}
}
function validateArray(_type, _value)
{
try
{
_value = JSON.parse(_value)
}
catch (e)
{
return { valid: false, message: "Input must be JSON formatted like [1,5,3,9] or [[4,9],[4,9],[4,9],[4,9]]" }
}
var dim = _type.match(arrayRegEx)
dim.reverse();
for (var k = 0; k < dim.length; k++)
_type = _type.replace(dim[k], "")
_type = _type.replace(/calldata/g, "")
return checkArrayRecursively(_type, dim, _value)
}
function isContractType(_type)
@ -100,7 +183,7 @@ function validateAddress(_type, _value)
function validateBytes(_type, _value)
{
var ret = { valid: true, message: "" }
if (_value.length > parseInt(_type.replace("bytes", "")) )
if (_type !== "bytes" && _value.length > parseInt(_type.replace("bytes", "")) )
{
ret.valid = false;
ret.message = _type + " should not contains more than " + _type.replace("bytes", "") + " characters";

3
mix/qml/js/ProjectModel.js

@ -254,7 +254,9 @@ function doCreateProject(title, path) {
files: [ contractsFile, indexFile ]
};
//TODO: copy from template
if (!fileIo.fileExists(dirPath + indexFile))
fileIo.writeFile(dirPath + indexFile, htmlTemplate);
if (!fileIo.fileExists(dirPath + contractsFile))
fileIo.writeFile(dirPath + contractsFile, contractTemplate);
newProject(projectData);
var json = JSON.stringify(projectData, null, "\t");
@ -342,6 +344,7 @@ function newContract() {
function createAndAddFile(name, extension, content) {
var fileName = generateFileName(name, extension);
var filePath = projectPath + fileName;
if (!fileIo.fileExists(filePath))
fileIo.writeFile(filePath, content);
var id = addFile(fileName);
saveProjectFile();

Loading…
Cancel
Save