Browse Source

Access to blockchain data.

cl-refactor
Christian 10 years ago
parent
commit
b185a748a5
  1. 31
      libsolidity/ExpressionCompiler.cpp
  2. 18
      libsolidity/GlobalContext.cpp
  3. 50
      libsolidity/Types.cpp
  4. 24
      libsolidity/Types.h
  5. 13
      test/solidityEndToEndTest.cpp

31
libsolidity/ExpressionCompiler.cpp

@ -212,10 +212,11 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
{
ASTString const& member = _memberAccess.getMemberName();
switch (_memberAccess.getExpression().getType()->getCategory())
{
case Type::Category::INTEGER:
if (asserts(_memberAccess.getMemberName() == "balance"))
if (asserts(member == "balance"))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
m_context << eth::Instruction::BALANCE;
break;
@ -224,12 +225,36 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Contract variables not yet implemented."));
break;
case Type::Category::MAGIC:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Magic variables not yet implemented."));
// we can ignore the kind of magic and only look at the name of the member
if (member == "coinbase")
m_context << eth::Instruction::COINBASE;
else if (member == "timestamp")
m_context << eth::Instruction::TIMESTAMP;
else if (member == "prevhash")
m_context << eth::Instruction::PREVHASH;
else if (member == "difficulty")
m_context << eth::Instruction::DIFFICULTY;
else if (member == "number")
m_context << eth::Instruction::NUMBER;
else if (member == "gaslimit")
m_context << eth::Instruction::GASLIMIT;
else if (member == "sender")
m_context << eth::Instruction::CALLER;
else if (member == "value")
m_context << eth::Instruction::CALLVALUE;
else if (member == "origin")
m_context << eth::Instruction::ORIGIN;
else if (member == "gas")
m_context << eth::Instruction::GAS;
else if (member == "gasprice")
m_context << eth::Instruction::GASPRICE;
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member."));
break;
case Type::Category::STRUCT:
{
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD;
m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::STORAGE);
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
break;

18
libsolidity/GlobalContext.cpp

@ -32,15 +32,17 @@ namespace dev
namespace solidity
{
GlobalContext::GlobalContext()
GlobalContext::GlobalContext():
m_magicVariables{make_shared<MagicVariableDeclaration>(MagicVariableDeclaration::VariableKind::BLOCK,
"block",
make_shared<MagicType>(MagicType::Kind::BLOCK)),
make_shared<MagicVariableDeclaration>(MagicVariableDeclaration::VariableKind::MSG,
"msg",
make_shared<MagicType>(MagicType::Kind::MSG)),
make_shared<MagicVariableDeclaration>(MagicVariableDeclaration::VariableKind::TX,
"tx",
make_shared<MagicType>(MagicType::Kind::TX))}
{
// CurrentContract this; // @todo type depends on context -> switch prior to entering contract
// Message msg;
// Transaction tx;
// Block block;
//@todo type will be a custom complex type, maybe the same type class for msg tx and block.
//addVariable("msg", );
}
void GlobalContext::setCurrentContract(ContractDefinition const& _contract)

50
libsolidity/Types.cpp

@ -333,5 +333,55 @@ bool TypeType::operator==(Type const& _other) const
return *getActualType() == *other.getActualType();
}
MagicType::MagicType(MagicType::Kind _kind):
m_kind(_kind)
{
switch (m_kind)
{
case Kind::BLOCK:
m_members = MemberList({{"coinbase", make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS)},
{"timestamp", make_shared<IntegerType const>(256)},
{"prevhash", make_shared<IntegerType const>(256, IntegerType::Modifier::HASH)},
{"difficulty", make_shared<IntegerType const>(256)},
{"number", make_shared<IntegerType const>(256)},
{"gaslimit", make_shared<IntegerType const>(256)}});
break;
case Kind::MSG:
m_members = MemberList({{"sender", make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS)},
{"value", make_shared<IntegerType const>(256)}});
break;
case Kind::TX:
m_members = MemberList({{"origin", make_shared<IntegerType const>(0, IntegerType::Modifier::ADDRESS)},
{"gas", make_shared<IntegerType const>(256)},
{"gasprice", make_shared<IntegerType const>(256)}});
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));
}
}
bool MagicType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
MagicType const& other = dynamic_cast<MagicType const&>(_other);
return other.m_kind == m_kind;
}
string MagicType::toString() const
{
switch (m_kind)
{
case Kind::BLOCK:
return "block";
case Kind::MSG:
return "msg";
case Kind::TX:
return "tx";
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));
}
}
}
}

24
libsolidity/Types.h

@ -327,5 +327,29 @@ private:
};
/**
* Special type for magic variables (block, msg, tx), similar to a struct but without any reference
* (it always references a global singleton by name).
*/
class MagicType: public Type
{
public:
enum class Kind { BLOCK, MSG, TX }; //@todo should be unified with MagicVariableDeclaration::VariableKind;
virtual Category getCategory() const override { return Category::MAGIC; }
MagicType(Kind _kind);
virtual bool operator==(Type const& _other) const;
virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; }
virtual MemberList const& getMembers() const override { return m_members; }
virtual std::string toString() const override;
private:
Kind m_kind;
MemberList m_members;
};
}
}

13
test/solidityEndToEndTest.cpp

@ -761,6 +761,19 @@ BOOST_AUTO_TEST_CASE(balance)
BOOST_CHECK(callContractFunction(0) == toBigEndian(u256(23)));
}
BOOST_AUTO_TEST_CASE(blockchain)
{
char const* sourceCode = "contract test {\n"
" function someInfo() returns (uint256 value, address coinbase, uint256 blockNumber) {\n"
" value = msg.value;\n"
" coinbase = block.coinbase;\n"
" blockNumber = block.number;\n"
" }\n"
"}\n";
compileAndRun(sourceCode, 27);
BOOST_CHECK(callContractFunction(0, bytes{0}, u256(28)) == toBigEndian(u256(28)) + bytes(20, 0) + toBigEndian(u256(1)));
}
BOOST_AUTO_TEST_SUITE_END()
}

Loading…
Cancel
Save