diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 7fa5b411a..b00a80c04 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -85,8 +85,8 @@ public: // The obvious comparison operators. bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; } - bool operator<(FixedHash const& _c) const { return m_data < _c.m_data; } - bool operator>=(FixedHash const& _c) const { return m_data >= _c.m_data; } + bool operator<(FixedHash const& _c) const { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; } + bool operator>=(FixedHash const& _c) const { return !operator<(_c); } // The obvious binary operators. FixedHash& operator^=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] ^= _c.m_data[i]; return *this; } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index c91c433ed..c3c2cd8d3 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -1197,7 +1197,13 @@ public: Wei = Token::SubWei, Szabo = Token::SubSzabo, Finney = Token::SubFinney, - Ether = Token::SubEther + Ether = Token::SubEther, + Second = Token::SubSecond, + Minute = Token::SubMinute, + Hour = Token::SubHour, + Day = Token::SubDay, + Week = Token::SubWeek, + Year = Token::SubYear }; Literal(SourceLocation const& _location, Token::Value _token, ASTPointer const& _value, diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 793bd55e4..adaaff23e 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -258,6 +258,9 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) case Token::BitNot: // ~ m_context << eth::Instruction::NOT; break; + case Token::After: // after + m_context << eth::Instruction::TIMESTAMP << eth::Instruction::ADD; + break; case Token::Delete: // delete solAssert(!!m_currentLValue, "LValue not retrieved."); m_currentLValue->setToZero(_unaryOperation.getLocation()); diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 3c88efc7c..44d111591 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -822,6 +822,15 @@ ASTPointer Parser::parsePrimaryExpression() expression = nodeFactory.createNode(token, literal, subdenomination); break; } + if (Token::isTimeSubdenomination(m_scanner->peekNextToken())) + { + ASTPointer literal = getLiteralAndAdvance(); + nodeFactory.markEndPosition(); + Literal::SubDenomination subdenomination = static_cast(m_scanner->getCurrentToken()); + m_scanner->next(); + expression = nodeFactory.createNode(token, literal, subdenomination); + break; + } // fall-through case Token::StringLiteral: nodeFactory.markEndPosition(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 19afaee3a..85979b566 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -163,7 +163,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Internal, "internal", 0) \ + K(Internal, "internal", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -172,11 +172,18 @@ namespace solidity K(While, "while", 0) \ K(Enum, "enum", 0) \ \ - /* Ether subdenominations */ \ - K(SubWei, "wei", 0) \ - K(SubSzabo, "szabo", 0) \ - K(SubFinney, "finney", 0) \ - K(SubEther, "ether", 0) \ + /* Ether subdenominations */ \ + K(SubWei, "wei", 0) \ + K(SubSzabo, "szabo", 0) \ + K(SubFinney, "finney", 0) \ + K(SubEther, "ether", 0) \ + K(SubSecond, "seconds", 0) \ + K(SubMinute, "minutes", 0) \ + K(SubHour, "hours", 0) \ + K(SubDay, "days", 0) \ + K(SubWeek, "weeks", 0) \ + K(SubYear, "years", 0) \ + K(After, "after", 0) \ /* type keywords, keep them in this order, keep int as first keyword * the implementation in Types.cpp has to be synced to this here */\ K(Int, "int", 0) \ @@ -377,12 +384,13 @@ public: } static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; } - static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; } + static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub || op == After; } static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } - static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } + static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; } + static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; } // Returns a string corresponding to the JS token string // (.e., "<" for the token LT) or NULL if the token doesn't diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 96feefff5..caa3b7169 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -195,7 +195,8 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const return TypePointer(); // for non-hash integers, we allow +, -, ++ and -- else if (_operator == Token::Add || _operator == Token::Sub || - _operator == Token::Inc || _operator == Token::Dec) + _operator == Token::Inc || _operator == Token::Dec || + _operator == Token::After) return shared_from_this(); else return TypePointer(); @@ -251,6 +252,7 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) switch (_literal.getSubDenomination()) { case Literal::SubDenomination::Wei: + case Literal::SubDenomination::Second: case Literal::SubDenomination::None: break; case Literal::SubDenomination::Szabo: @@ -262,6 +264,21 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) case Literal::SubDenomination::Ether: m_value *= bigint("1000000000000000000"); break; + case Literal::SubDenomination::Minute: + m_value *= bigint("60"); + break; + case Literal::SubDenomination::Hour: + m_value *= bigint("3600"); + break; + case Literal::SubDenomination::Day: + m_value *= bigint("86400"); + break; + case Literal::SubDenomination::Week: + m_value *= bigint("604800"); + break; + case Literal::SubDenomination::Year: + m_value *= bigint("31536000"); + break; } } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 2ce9455cf..781924db7 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -46,15 +46,18 @@ const u256 c_mixGenesisDifficulty = (u256) 1 << 4; class MixBlockChain: public dev::eth::BlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, true) + MixBlockChain(std::string const& _path, h256 _stateRoot): + BlockChain(createGenesisBlock(_stateRoot), _path, true) { } static bytes createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(14) - << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << std::string() << sha3(bytes(1, 42)); + block.appendList(16) + << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie + << LogBloom() << c_mixGenesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 + << std::string() << h256() << h256() << h64(u64(42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); diff --git a/test/SolidityScanner.cpp b/test/SolidityScanner.cpp index 2e4e5db08..8d3e53929 100644 --- a/test/SolidityScanner.cpp +++ b/test/SolidityScanner.cpp @@ -264,6 +264,23 @@ BOOST_AUTO_TEST_CASE(ether_subdenominations) BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther); } +BOOST_AUTO_TEST_CASE(time_subdenominations) +{ + Scanner scanner(CharStream("seconds minutes hours days weeks years")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::SubSecond); + BOOST_CHECK_EQUAL(scanner.next(), Token::SubMinute); + BOOST_CHECK_EQUAL(scanner.next(), Token::SubHour); + BOOST_CHECK_EQUAL(scanner.next(), Token::SubDay); + BOOST_CHECK_EQUAL(scanner.next(), Token::SubWeek); + BOOST_CHECK_EQUAL(scanner.next(), Token::SubYear); +} + +BOOST_AUTO_TEST_CASE(time_after) +{ + Scanner scanner(CharStream("after 1")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::After); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/blockchain.cpp b/test/blockchain.cpp index ccfd57722..aea2bab07 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -78,8 +78,8 @@ bytes createBlockRLPFromFields(mObject& _tObj) if (_tObj.count("seedHash")) rlpStream << importByteArray(_tObj["seedHash"].get_str()); - if (_tObj.count("mixBytes")) - rlpStream << importByteArray(_tObj["mixBytes"].get_str()); + if (_tObj.count("mixHash")) + rlpStream << importByteArray(_tObj["mixHash"].get_str()); if (_tObj.count("nonce")) rlpStream << importByteArray(_tObj["nonce"].get_str()); @@ -146,7 +146,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) //update genesis block in json file o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot); o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce); - o["genesisBlockHeader"].get_obj()["mixBytes"] = toString(blockFromFields.mixBytes); + o["genesisBlockHeader"].get_obj()["mixHash"] = toString(blockFromFields.mixHash); } // create new "genesis" block @@ -276,8 +276,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (blObj["blockHeader"].get_obj().count("extraData")) tmp.extraData = importByteArray(blObj["blockHeader"].get_obj()["extraData"].get_str()); - if (blObj["blockHeader"].get_obj().count("mixBytes")) - tmp.mixBytes = h256(blObj["blockHeader"].get_obj()["mixBytes"].get_str()); + if (blObj["blockHeader"].get_obj().count("mixHash")) + tmp.mixHash = h256(blObj["blockHeader"].get_obj()["mixHash"].get_str()); if (blObj["blockHeader"].get_obj().count("seedHash")) tmp.seedHash = h256(blObj["blockHeader"].get_obj()["seedHash"].get_str()); @@ -322,7 +322,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); - oBlockHeader["mixBytes"] = toString(current_BlockHeader.mixBytes); + oBlockHeader["mixHash"] = toString(current_BlockHeader.mixHash); oBlockHeader["seedHash"] = toString(current_BlockHeader.seedHash); oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); @@ -445,7 +445,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixBytes == blockFromRlp.mixBytes, "mixBytes in given RLP not matching the block mixBytes!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.seedHash == blockFromRlp.seedHash, "transactionsRoot in given RLP not matching the block transactionsRoot!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!");