未验证 提交 5985cc40 编写于 作者: W wanderingbort 提交者: GitHub

Merge pull request #6364 from EOSIO/features/merge-v1.5.0-rc1

v1.5.0 rc1
<!-- PLEASE FILL OUT THE FOLLOWING MARKDOWN TEMPLATE -->
<!-- Give your PR a title that is sufficient to understand what is being changed. -->
**Change Description**
## Change Description
<!-- Describe the change you made, the motivation for it, and the impact it will have. Reference issues or pull requests where possible (use '#XX' or 'GH-XX' where XX is the issue or pull request number). -->
**Consensus Changes**
## Consensus Changes
<!-- If this PR introduces a change to the validation of blocks in the chain or consensus in general, please describe the impact. -->
**API Changes**
## API Changes
<!-- If this PR introduces API changes, please describe the changes here. What will developers need to know before upgrading to this version? -->
**Documentation Additions**
## Documentation Additions
<!-- List all the information that needs to be added to the documentation after merge. -->
......@@ -34,8 +34,8 @@ set( CMAKE_CXX_EXTENSIONS ON )
set( CXX_STANDARD_REQUIRED ON)
set(VERSION_MAJOR 1)
set(VERSION_MINOR 4)
set(VERSION_PATCH 4)
set(VERSION_MINOR 5)
set(VERSION_PATCH 0-rc1)
set( CLI_CLIENT_EXECUTABLE_NAME cleos )
set( NODE_EXECUTABLE_NAME nodeos )
......
......@@ -97,8 +97,8 @@ macro(add_eosio_test test_name)
${liblogging}
${libchainbase}
${libbuiltins}
${GMP_LIBRARIES}
${libsecp256k1}
${GMP_LIBRARIES}
LLVMX86Disassembler
LLVMX86AsmParser
......
......@@ -98,8 +98,8 @@ macro(add_eosio_test test_name)
${liblogging}
${libchainbase}
${libbuiltins}
${GMP_LIBRARIES}
${libsecp256k1}
${GMP_LIBRARIES}
LLVMX86Disassembler
LLVMX86AsmParser
......
......@@ -6,7 +6,7 @@ RUN git clone -b $branch https://github.com/EOSIO/eos.git --recursive \
&& cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \
&& cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \
&& cmake --build /tmp/build --target install && rm /tmp/build/bin/eosiocpp
&& cmake --build /tmp/build --target install
FROM ubuntu:18.04
......
......@@ -20,10 +20,10 @@ cd eos/Docker
docker build . -t eosio/eos
```
The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.4.4 tag, you could do the following:
The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.5.0-rc1 tag, you could do the following:
```bash
docker build -t eosio/eos:v1.4.4 --build-arg branch=v1.4.4 .
docker build -t eosio/eos:v1.5.0-rc1 --build-arg branch=v1.5.0-rc1 .
```
By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image.
......
......@@ -39,13 +39,13 @@ $ brew remove eosio
```
#### Ubuntu 18.04 Debian Package Install
```sh
$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio_1.4.4-1-ubuntu-18.04_amd64.deb
$ sudo apt install ./eosio_1.4.4-1-ubuntu-18.04_amd64.deb
$ wget https://github.com/eosio/eos/releases/download/v1.5.0-rc1/eosio_1.5.0-rc1-1-ubuntu-18.04_amd64.deb
$ sudo apt install ./eosio_1.5.0-rc1-1-ubuntu-18.04_amd64.deb
```
#### Ubuntu 16.04 Debian Package Install
```sh
$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio_1.4.4-1-ubuntu-16.04_amd64.deb
$ sudo apt install ./eosio_1.4.4-1-ubuntu-16.04_amd64.deb
$ wget https://github.com/eosio/eos/releases/download/v1.5.0-rc1/eosio_1.5.0-rc1-1-ubuntu-16.04_amd64.deb
$ sudo apt install ./eosio_1.5.0-rc1-1-ubuntu-16.04_amd64.deb
```
#### Debian Package Uninstall
```sh
......@@ -53,8 +53,8 @@ $ sudo apt remove eosio
```
#### Centos RPM Package Install
```sh
$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio-1.4.4-1.el7.x86_64.rpm
$ sudo yum install ./eosio-1.4.4-1.el7.x86_64.rpm
$ wget https://github.com/eosio/eos/releases/download/v1.5.0-rc1/eosio-1.5.0-rc1-1.el7.x86_64.rpm
$ sudo yum install ./eosio-1.5.0-rc1-1.el7.x86_64.rpm
```
#### Centos RPM Package Uninstall
```sh
......@@ -62,8 +62,8 @@ $ sudo yum remove eosio.cdt
```
#### Fedora RPM Package Install
```sh
$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio-1.4.4-1.fc27.x86_64.rpm
$ sudo yum install ./eosio-1.4.4-1.fc27.x86_64.rpm
$ wget https://github.com/eosio/eos/releases/download/v1.5.0-rc1/eosio-1.5.0-rc1-1.fc27.x86_64.rpm
$ sudo yum install ./eosio-1.5.0-rc1-1.fc27.x86_64.rpm
```
#### Fedora RPM Package Uninstall
```sh
......
......@@ -7,7 +7,6 @@ set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_BINARY_DIR}/c
add_subdirectory(eosiolib)
add_subdirectory(musl)
add_subdirectory(libc++)
add_subdirectory(simple.token)
add_subdirectory(eosio.token)
add_subdirectory(eosio.msig)
add_subdirectory(eosio.sudo)
......@@ -18,17 +17,14 @@ add_subdirectory(identity)
add_subdirectory(stltest)
add_subdirectory(test.inline)
#add_subdirectory(bancor)
add_subdirectory(hello)
add_subdirectory(asserter)
add_subdirectory(infinite)
add_subdirectory(proxy)
add_subdirectory(test_api)
add_subdirectory(test_api_mem)
add_subdirectory(test_api_db)
add_subdirectory(test_api_multi_index)
add_subdirectory(test_ram_limit)
#add_subdirectory(social)
add_subdirectory(eosio.bios)
add_subdirectory(noop)
add_subdirectory(tic_tac_toe)
......
file(GLOB ABI_FILES "*.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_executable(TARGET bancor
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES libc libc++ eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <bancor/bancor.hpp>
namespace bancor {
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t r, uint64_t c, uint64_t a ) {
bancor::example_converter::apply( c, a );
}
}
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/eosio.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/reflect.hpp>
#include <eosiolib/generic_currency.hpp>
#include <bancor/converter.hpp>
#include <currency/currency.hpp>
namespace bancor {
typedef eosio::generic_currency< eosio::token<N(other),S(4,OTHER)> > other_currency;
typedef eosio::generic_currency< eosio::token<N(bancor),S(4,RELAY)> > relay_currency;
typedef eosio::generic_currency< eosio::token<N(currency),S(4,CUR)> > cur_currency;
typedef converter<relay_currency, other_currency, cur_currency > example_converter;
} /// bancor
#pragma once
namespace bancor {
template<typename ConverterCurrency, typename FirstCurrency, typename SecondCurrency>
class converter_contract {
public:
typedef ConverterCurrency converter_currency;
typedef FirstCurrency first_currency;
typedef SecondCurrency second_currency;
static const account_name converter_account = converter_currency::code;
struct converter_state {
typename converter_currency::token_type supply; /// total supply held by all users
typename converter_currency::token_type balance; /// supply held by converter in its own balance
};
struct converter_args {
eosio::account_name to_currency_account;
eosio::symbol_name to_currency_symbol;
uint64_t min_return_currency;
};
template<typename CurrencyType, uint32_t Weight=500000, uint32_t Base=1000000>
struct connector {
typedef CurrencyType currency_type;
typedef typename converter_currency::token_type converter_token_type;
typedef typename currency_type::token_type in_token_type;
converter_token_type convert_to_converter( in_token_type in, converter_state& state ) {
in_token_type balance = currency_type::get_balance( converter_account );
/// balance already changed when transfer executed, get pre-transfer balance
in_token_type previous_balance = balance - in;
auto init_price = (previous_balance * Base) / (Weight * state.supply);
auto init_out = init_price * in;
auto out_price = (balance*Base) / (Weight * (state.supply+init_out) );
auto final_out = out_price * in;
state.balance += final_out;
state.supply += final_out;
return final_out;
}
in_token_type convert_from_converter( converter_token_type converter_in, converter_state& state ) {
in_token_type to_balance = CurrencyType::get_balance( converter_account );
auto init_price = (to_balance * Base) / (Weight * state.supply);
in_token_type init_out = init_price * converter_in;
state.supply -= converter_in;
state.balance -= converter_in;
auto out_price = ((to_balance-init_out) * Base) / ( Weight * (state.supply) );
return out_price * converter_in;
}
};
/**
* This is called when we receive RELAY tokens from user and wish to
* convert to one of the connector currencies.
*/
static void on_convert( const typename converter_currency::transfer& trans,
const converter_args& args,
converter_state& state ) {
if( args.to_currency_type == first_currency ) {
auto output = first_connector::convert_from_converter( trans.quantity, state );
save_and_send( trans.from, state, output, args.min_return );
}
else if( args.to_currency_type == second_currency ) {
auto output = second_connector::convert_from_converter( trans.quantity, state );
save_and_send( trans.from, state, output, args.min_return );
}
else {
eosio_assert( false, "invalid to currency" );
}
}
/**
* This is called when the converter receives one of the connector currencies and it
* will send either converter tokens or a different connector currency in response.
*/
template<typename ConnectorType>
static void on_convert( const typename ConnectorType::currency_type::transfer& trans,
const converter_args& args,
converter_state& state )
{
/// convert to converter
auto converter_out = ConnectorType::convert_to_converter( trans.quantity, state );
if( args.to_currency_type == converter_currency )
{
save_and_send( trans.from, state, converter_out, args.min_return );
}
else
{
auto output = ConnectorType::convert_from_converter( converter_out, state );
save_and_send( trans.from, state, output, args.min_return );
}
}
/**
* This method factors out the boiler plate for parsing args and loading the
* initial state before dispatching to the proper on_convert case
*/
template<typename CurrencyType>
static void start_convert( const typename CurrencyType::transfer_memo& trans ) {
auto args = unpack<converter_args>( trans.memo );
eosio_assert( args.to_currency_type != trans.quantity.token_type(), "cannot convert to self" );
auto state = read_converter_state();
on_convert( trans, args, state );
}
/**
* converter_account first needs to call the currency handler to perform
* user-to-user transfers of the converter token, then if a transfer is sending
* the token back to the converter contract, it should convert like everything else.
*
* This method should be called from apply( code, action ) for each of the
* transfer types that we support (for each currency)
*/
static void on( const typename converter_currency::transfer_memo& trans ) {
converter_currency::on( trans );
if( trans.to == converter_account ) {
start_convert( trans );
}
}
/**
* All other currencies simply call start_convert if to == converter_account
*/
template<typename Currency>
static void on( const typename Currency::transfer_memo& trans ) {
if( trans.to == converter_account ) {
start_convert( trans );
} else {
eosio_assert( trans.from == converter_account,
"received unexpected notification of transfer" );
}
}
static void apply( account_name code, action_name action ) {
if( !dispatch( converter_contract,
converter_currency::transfer,
converter_currency::issue,
first_currency::transfer,
second_currency::transfer ) {
eosio_assert( false, "received unexpected action" );
}
}
}; /// converter_contract
} /// namespace bancor
{
"types": [{
"new_type_name": "account_name",
"type": "name"
}
],
"structs": [{
"name": "transfer",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"uint64"}
]
},{
"name": "account",
"base": "",
"fields": [
{"name":"key", "type":"name"},
{"name":"balance", "type":"uint64"}
]
}
],
"actions": [{
"name": "transfer",
"type": "transfer"
}
],
"tables": [{
"name": "account",
"type": "account",
"index_type": "i64",
"key_names" : ["key"],
"key_types" : ["name"]
}
]
}
\ No newline at end of file
#pragma once
#include <eosiolib/eosio.hpp>
#include <eosiolib/asset.hpp>
#include <eosiolib/multi_index.hpp>
namespace eosio {
using std::string;
using std::array;
/**
* This contract enables the creation, issuance, and transfering of many different tokens.
* @deprecated This class is deprecated in favor of eosio.token in Dawn 3.0
*/
class currency {
public:
currency( account_name contract )
:_contract(contract)
{ }
struct create {
account_name issuer;
asset maximum_supply;
// array<char,32> issuer_agreement_hash;
uint8_t issuer_can_freeze = true;
uint8_t issuer_can_recall = true;
uint8_t issuer_can_whitelist = true;
/*(issuer_agreement_hash)*/
EOSLIB_SERIALIZE( create, (issuer)(maximum_supply)(issuer_can_freeze)(issuer_can_recall)(issuer_can_whitelist) )
};
struct transfer
{
account_name from;
account_name to;
asset quantity;
string memo;
EOSLIB_SERIALIZE( transfer, (from)(to)(quantity)(memo) )
};
struct issue {
account_name to;
asset quantity;
string memo;
EOSLIB_SERIALIZE( issue, (to)(quantity)(memo) )
};
struct fee_schedule {
uint64_t primary_key()const { return 0; }
array<extended_asset,7> fee_per_length;
EOSLIB_SERIALIZE( fee_schedule, (fee_per_length) )
};
struct account {
asset balance;
bool frozen = false;
bool whitelist = true;
uint64_t primary_key()const { return balance.symbol.name(); }
EOSLIB_SERIALIZE( account, (balance)(frozen)(whitelist) )
};
struct currency_stats {
asset supply;
asset max_supply;
account_name issuer;
bool can_freeze = true;
bool can_recall = true;
bool can_whitelist = true;
bool is_frozen = false;
bool enforce_whitelist = false;
uint64_t primary_key()const { return supply.symbol.name(); }
EOSLIB_SERIALIZE( currency_stats, (supply)(max_supply)(issuer)(can_freeze)(can_recall)(can_whitelist)(is_frozen)(enforce_whitelist) )
};
typedef eosio::multi_index<N(accounts), account> accounts;
typedef eosio::multi_index<N(stat), currency_stats> stats;
asset get_balance( account_name owner, symbol_name symbol )const {
accounts t( _contract, owner );
return t.get(symbol).balance;
}
asset get_supply( symbol_name symbol )const {
accounts t( _contract, symbol );
return t.get(symbol).balance;
}
static void inline_transfer( account_name from, account_name to, extended_asset amount, string memo = string(), permission_name perm = N(active) ) {
action act( permission_level( from, perm ), amount.contract, N(transfer), transfer{from,to,amount,memo} );
act.send();
}
void inline_transfer( account_name from, account_name to, asset amount, string memo = string(), permission_name perm = N(active) ) {
action act( permission_level( from, perm ), _contract, N(transfer), transfer{from,to,amount,memo} );
act.send();
}
bool apply( account_name contract, action_name act ) {
if( contract != _contract )
return false;
switch( act ) {
case N(issue):
print( "issue\n");
on( unpack_action_data<issue>() );
return true;
case N(transfer):
print( "transfer\n");
on( unpack_action_data<transfer>() );
return true;
case N(create):
print( "create\n");
on( unpack_action_data<create>() );
return true;
}
return false;
}
/**
* This is factored out so it can be used as a building block
*/
void create_currency( const create& c ) {
auto sym = c.maximum_supply.symbol;
eosio_assert( sym.is_valid(), "invalid symbol name" );
stats statstable( _contract, sym.name() );
auto existing = statstable.find( sym.name() );
eosio_assert( existing == statstable.end(), "token with symbol already exists" );
statstable.emplace( c.issuer, [&]( auto& s ) {
s.supply.symbol = c.maximum_supply.symbol;
s.max_supply = c.maximum_supply;
s.issuer = c.issuer;
s.can_freeze = c.issuer_can_freeze;
s.can_recall = c.issuer_can_recall;
s.can_whitelist = c.issuer_can_whitelist;
});
}
void issue_currency( const issue& i ) {
auto sym = i.quantity.symbol.name();
stats statstable( _contract, sym );
const auto& st = statstable.get( sym );
statstable.modify( st, 0, [&]( auto& s ) {
s.supply.amount += i.quantity.amount;
eosio_assert( s.supply.amount >= 0, "underflow" );
});
add_balance( st.issuer, i.quantity, st, st.issuer );
}
void on( const create& c ) {
require_auth( c.issuer );
create_currency( c );
/*
auto fee = get_fee_schedule()[c.maximum_supply.name_length()];
if( fee.amount > 0 ) {
inline_transfer( c.issuer, _contract, fee, "symbol registration fee" );
}
*/
}
void on( const issue& i ) {
auto sym = i.quantity.symbol.name();
stats statstable( _contract, sym );
const auto& st = statstable.get( sym );
require_auth( st.issuer );
eosio_assert( i.quantity.is_valid(), "invalid quantity" );
eosio_assert( i.quantity.amount > 0, "must issue positive quantity" );
statstable.modify( st, 0, [&]( auto& s ) {
s.supply.amount += i.quantity.amount;
});
add_balance( st.issuer, i.quantity, st, st.issuer );
if( i.to != st.issuer )
{
inline_transfer( st.issuer, i.to, i.quantity, i.memo );
}
}
void on( const transfer& t ) {
require_auth(t.from);
auto sym = t.quantity.symbol.name();
stats statstable( _contract, sym );
const auto& st = statstable.get( sym );
require_recipient( t.to );
eosio_assert( t.quantity.is_valid(), "invalid quantity" );
eosio_assert( t.quantity.amount > 0, "must transfer positive quantity" );
sub_balance( t.from, t.quantity, st );
add_balance( t.to, t.quantity, st, t.from );
}
private:
void sub_balance( account_name owner, asset value, const currency_stats& st ) {
accounts from_acnts( _contract, owner );
const auto& from = from_acnts.get( value.symbol.name() );
eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );
if( has_auth( owner ) ) {
eosio_assert( !st.can_freeze || !from.frozen, "account is frozen by issuer" );
eosio_assert( !st.can_freeze || !st.is_frozen, "all transfers are frozen by issuer" );
eosio_assert( !st.enforce_whitelist || from.whitelist, "account is not white listed" );
} else if( has_auth( st.issuer ) ) {
eosio_assert( st.can_recall, "issuer may not recall token" );
} else {
eosio_assert( false, "insufficient authority" );
}
from_acnts.modify( from, owner, [&]( auto& a ) {
a.balance.amount -= value.amount;
});
}
void add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer )
{
accounts to_acnts( _contract, owner );
auto to = to_acnts.find( value.symbol.name() );
if( to == to_acnts.end() ) {
eosio_assert( !st.enforce_whitelist, "can only transfer to white listed accounts" );
to_acnts.emplace( ram_payer, [&]( auto& a ){
a.balance = value;
});
} else {
eosio_assert( !st.enforce_whitelist || to->whitelist, "receiver requires whitelist by issuer" );
to_acnts.modify( to, 0, [&]( auto& a ) {
a.balance.amount += value.amount;
});
}
}
private:
account_name _contract;
};
}
add_wast_executable(TARGET infinite
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES libc++ libc eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/print.hpp> /// defines transfer struct (abi)
extern "C" {
/// The apply method just prints forever
void apply( uint64_t, uint64_t, uint64_t ) {
int idx = 0;
while(true) {
eosio::print(idx++);
}
}
}
file(GLOB ABI_FILES "*.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_executable(TARGET simple.token
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES libc++ libc eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
#include <eosiolib/eosio.hpp>
class simpletoken : public eosio::contract {
public:
simpletoken( account_name self )
:contract(self),_accounts( _self, _self){}
void transfer( account_name from, account_name to, uint64_t quantity ) {
require_auth( from );
const auto& fromacnt = _accounts.get( from );
eosio_assert( fromacnt.balance >= quantity, "overdrawn balance" );
_accounts.modify( fromacnt, from, [&]( auto& a ){ a.balance -= quantity; } );
add_balance( from, to, quantity );
}
void issue( account_name to, uint64_t quantity ) {
require_auth( _self );
add_balance( _self, to, quantity );
}
private:
struct account {
account_name owner;
uint64_t balance;
uint64_t primary_key()const { return owner; }
};
eosio::multi_index<N(accounts), account> _accounts;
void add_balance( account_name payer, account_name to, uint64_t q ) {
auto toitr = _accounts.find( to );
if( toitr == _accounts.end() ) {
_accounts.emplace( payer, [&]( auto& a ) {
a.owner = to;
a.balance = q;
});
} else {
_accounts.modify( toitr, 0, [&]( auto& a ) {
a.balance += q;
eosio_assert( a.balance >= q, "overflow detected" );
});
}
}
};
EOSIO_ABI( simpletoken, (transfer)(issue) )
add_wast_executable(TARGET social
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eos.hpp>
/**
* The purpose of this contract is to implement something like Steem on EOS, this
* means this contract defines its own currency, allows people to create posts, vote
* on posts, and stake their voting power.
*
* Unlike Steem, the goal is to enable maximum parallelism and enable the currency to
* be easily integrated with an exchange contract.
*/
struct post_action {
account_name author;
post_name postid;
account_name reply_to_author;
int32_t reply_to_id;
uint8_t author; /// index in notify list
char[] data; /// ignored, title is embedded within
account_name get_author()const { return get_notify(author); }
};
struct vote_action {
account_name voter;
account_name author;
post_name postid;
int32_t vote_power;
};
struct post_record {
uint64_t total_votes = 0;
uint64_t claimed_votes = 0;
uint32_t created;
post_record( uint32_t c = now() ):created(c){}
static Name table_id() { return Name("post"); }
};
struct account {
uint64_t social = 0;
uint64_t social_power = 0;
int32_t vote_power = 0;
uint32_t last_vote = 0;
static Name table_id() { return Name("account"); }
};
/**
* When a user posts we create a record that tracks the total votes and the time it
* was created. A user can submit this action multiple times, but subsequent calls do
* nothing.
*
* This method only does something when called in the context of the author, if
* any other contexts are notified
*/
void apply_social_post() {
const auto& post = current_action<post_action>();
require_auth( post.author );
eosio_assert( current_context() == post.author, "cannot call from any other context" );
static post_record& existing;
if( !Db::get( post.postid, existing ) )
Db::store( post.postid, post_record( now() ) );
}
/**
* This action is called when a user casts a vote, it requires that this code is executed
* in the context of both the voter and the author. When executed in the author's context it
* updates the vote total. When executed
*/
void apply_social_vote() {
const auto& vote = current_action<vote_action>();
require_recipient( vote.voter, vote.author );
disable_context_code( vote.author() ); /// prevent the author's code from rejecting the potentially negative vote
auto context = current_context();
auto voter = vote.getVoter();
if( context == vote.author ) {
static post_record post;
eosio_assert( Db::get( vote.postid, post ) > 0, "unable to find post" );
eosio_assert( now() - post.created < days(7), "cannot vote after 7 days" );
post.votes += vote.vote_power;
Db::store( vote.postid, post );
}
else if( context == vote.voter ) {
static account vote_account;
Db::get( "account", vote_account );
auto abs_vote = abs(vote.vote_power);
vote_account.vote_power = min( vote_account.social_power,
vote_account.vote_power + (vote_account.social_power * (now()-last_vote)) / days(7));
eosio_assert( abs_vote <= vote_account.vote_power, "insufficient vote power" );
post.votes += vote.vote_power;
vote_account.vote_power -= abs_vote;
vote_account.last_vote = now();
Db::store( "account", vote_account );
} else {
eosio_assert( false, "invalid context for execution of this vote" );
}
}
......@@ -51,7 +51,7 @@ account_name get_winner(const tic_tac_toe::game& current_game) {
uint32_t consecutive_diagonal_backslash = 3;
uint32_t consecutive_diagonal_slash = 3;
for (uint32_t i = 0; i < board.size(); i++) {
is_board_full &= is_empty_cell(board[i]);
is_board_full &= !is_empty_cell(board[i]);
uint16_t row = uint16_t(i / tic_tac_toe::game::board_width);
uint16_t column = uint16_t(i % tic_tac_toe::game::board_width);
......
......@@ -3,11 +3,9 @@ add_subdirectory( builtins )
add_subdirectory( softfloat )
add_subdirectory( chainbase )
add_subdirectory( wasm-jit )
add_subdirectory( utilities )
add_subdirectory( appbase )
add_subdirectory( chain )
add_subdirectory( testing )
add_subdirectory( abi_generator )
#turn these off for now
set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests")
......
# Find an installed build of LLVM
find_package(LLVM 4.0 REQUIRED CONFIG)
set( CMAKE_CXX_STANDARD 14 )
file(GLOB HEADERS "include/eosio/abi_generator/*.hpp")
set(SOURCES ${HEADERS})
add_library( abi_generator
abi_generator.cpp
${HEADERS} )
target_include_directories(abi_generator
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
"${LLVM_INCLUDE_DIRS}")
target_link_libraries(abi_generator eosio_chain
clangRewrite
clangTooling
clangToolingCore
clangFrontend
clangDriver
clangSerialization
clangParse
clangSema
clangAnalysis
clangAST
clangBasic
clangEdit
clangLex
)
target_link_libraries(abi_generator
LLVMX86AsmParser # MC, MCParser, Support, X86CodeGen, X86Desc, X86Info
LLVMX86CodeGen # Analysis, AsmPrinter, CodeGen, Core, MC, Support, Target,
# X86AsmPrinter, X86Desc, X86Info, X86Utils
LLVMX86Desc # MC, MCDisassembler, Object, Support, X86AsmPrinter, X86Info
LLVMX86AsmPrinter # MC, Support, X86Utils
LLVMX86Info # Support
LLVMX86Utils # Core, Support
LLVMCodeGen # Analysis, Core, MC, Scalar, Support, Target, TransformUtils
LLVMipo
LLVMScalarOpts
LLVMInstCombine
LLVMTransformUtils
LLVMTarget # Analysis, MC, Core, Support
LLVMAnalysis # Core, Support
LLVMOption # Support
LLVMMCDisassembler # MC, Support
LLVMMCParser # MC, Support
LLVMMC # Object, Support
LLVMProfileData # Core, Support, Object
LLVMObject # BitReader, Core, Support
LLVMBitReader # Core, Support
LLVMCore # BinaryFormat, Support
#LLVMBinaryFormat # Support
LLVMSupport # Demangle
LLVMDemangle
)
if (USE_PCH)
set_target_properties(abi_generator PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
cotire(eos_utilities)
endif(USE_PCH)
此差异已折叠。
#pragma once
#include <set>
#include <regex>
#include <algorithm>
#include <memory>
#include <map>
#include <fstream>
#include <sstream>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/contract_types.hpp>
#include <fc/io/json.hpp>
//clashes with something deep in the AST includes in clang 6 and possibly other versions of clang
#pragma push_macro("N")
#undef N
#include "clang/Driver/Options.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Sema/Sema.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/MacroArgs.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Core/QualTypeNames.h"
#include "llvm/Support/raw_ostream.h"
#include <boost/algorithm/string.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
using namespace clang;
using namespace std;
using namespace clang::tooling;
namespace cl = llvm::cl;
namespace eosio {
using namespace eosio::chain;
FC_DECLARE_EXCEPTION( abi_generation_exception, 999999, "Unable to generate abi" );
#define ABI_ASSERT( TEST, ... ) \
FC_EXPAND_MACRO( \
FC_MULTILINE_MACRO_BEGIN \
if( UNLIKELY(!(TEST)) ) \
{ \
if( fc::enable_record_assert_trip ) \
fc::record_assert_trip( __FILE__, __LINE__, #TEST ); \
FC_THROW_EXCEPTION( eosio::abi_generation_exception, #TEST ": " __VA_ARGS__ ); \
} \
FC_MULTILINE_MACRO_END \
)
class ricardian_contracts {
public:
ricardian_contracts() = default;
ricardian_contracts( const string& context, const string& contract, const vector<string>& actions ) {
ifstream clauses_file( context+"/"+contract+"_rc.md");
if ( !clauses_file.good() )
wlog("Warning, no ricardian clauses found for ${con}\n", ("con", contract));
else
parse_clauses( clauses_file );
for ( auto act : actions ) {
ifstream contract_file( context+"/"+contract+"."+act+"_rc.md" );
if ( !contract_file.good() )
wlog("Warning, no ricardian contract found for ${act}\n", ("act", act));
else {
parse_contract( contract_file );
}
}
}
vector<clause_pair> get_clauses() {
return _clauses;
}
string operator[]( string key ) {
return _contracts[key];
}
private:
inline string is_clause_decl( string line ) {
smatch match;
if ( regex_match( line, match, regex("(###[ ]+CLAUSE[ ]+NAME[ ]*:[ ]*)(.*)", regex_constants::ECMAScript) ) ) {
EOS_ASSERT( match.size() == 3, invalid_ricardian_clause_exception, "Error, malformed clause declaration" );
return match[2].str();
}
return {};
}
inline string is_action_decl( string line ) {
smatch match;
if ( regex_match( line, match, regex("(##[ ]+ACTION[ ]+NAME[ ]*:[ ]*)(.*)", regex_constants::ECMAScript) ) ) {
EOS_ASSERT( match.size() == 3, invalid_ricardian_action_exception, "Error, malformed action declaration" );
return match[2].str();
}
return {};
}
void parse_contract( ifstream& contract_file ) {
string line;
string name;
string _name;
stringstream body;
bool first_time = true;
while ( contract_file.peek() != EOF ) {
getline( contract_file, line );
body << line;
if ( !(_name = is_action_decl( line )).empty() ) {
name = _name;
first_time = false;
}
else
if ( !first_time )
body << line << '\n';
}
_contracts.emplace(name, body.str());
}
void parse_clauses( ifstream& clause_file ) {
string line;
string name;
string _name;
stringstream body;
bool first_time = true;
while ( clause_file.peek() != EOF ) {
getline( clause_file, line );
if ( !(_name = is_clause_decl( line )).empty() ) {
if ( !first_time ) {
if (body.str().empty() ) {
EOS_ASSERT( false, invalid_ricardian_clause_exception, "Error, invalid input in ricardian clauses, no body found" );
}
_clauses.emplace_back( name, body.str() );
body.str("");
}
name = _name;
first_time = false;
}
else
if ( !first_time )
body << line << '\n';
}
}
vector<clause_pair> _clauses;
map<string, string> _contracts;
};
/**
* @brief Generates eosio::abi_def struct handling events from ASTConsumer
*/
class abi_generator {
private:
static constexpr size_t max_recursion_depth = 25; // arbitrary depth to prevent infinite recursion
bool verbose;
int optimizations;
abi_def* output;
CompilerInstance* compiler_instance;
map<string, uint64_t> type_size;
map<string, string> full_types;
string abi_context;
clang::ASTContext* ast_context;
string target_contract;
vector<string> target_actions;
ricardian_contracts rc;
public:
enum optimization {
OPT_SINGLE_FIELD_STRUCT
};
abi_generator()
: verbose(false)
, optimizations(0)
, output(nullptr)
, compiler_instance(nullptr)
, ast_context(nullptr)
{}
~abi_generator() {}
/**
* @brief Enable optimization when generating ABI
* @param o optimization to enable
*/
void enable_optimizaton(optimization o);
/**
* @brief Check if an optimization is enabled
* @param o optimization to check
*/
bool is_opt_enabled(optimization o);
/**
* @brief Set the destination ABI struct to write
* @param output ABI destination
*/
void set_output(abi_def& output);
/**
* @brief Enable/Disable verbose status messages
* @param verbose enable/disable flag
*/
void set_verbose(bool verbose);
/**
* @brief Set the root folder that limits where types will be imported. Types declared in header files located in child sub-folders will also be exported
* @param abi_context folder
*/
void set_abi_context(const string& abi_context);
/**
* @brief Set the ricardian_contracts object with parsed contracts and clauses
* @param ricardian_contracts contracts
*/
void set_ricardian_contracts(const ricardian_contracts& contracts);
/**
* @brief Set the single instance of the Clang compiler
* @param compiler_instance compiler instance
*/
void set_compiler_instance(CompilerInstance& compiler_instance);
/**
* @brief Handle declaration of struct/union/enum
* @param tag_decl declaration to handle
*/
void handle_tagdecl_definition(TagDecl* tag_decl);
void set_target_contract(const string& contract, const vector<string>& actions);
private:
bool inspect_type_methods_for_actions(const Decl* decl);
string remove_namespace(const string& full_name);
bool is_builtin_type(const string& type_name);
string translate_type(const string& type_name);
void handle_decl(const Decl* decl);
bool is_64bit(const string& type);
bool is_128bit(const string& type);
bool is_string(const string& type);
void get_all_fields(const struct_def& s, vector<field_def>& fields);
bool is_i64i64i64_index(const vector<field_def>& fields);
bool is_i64_index(const vector<field_def>& fields);
bool is_i128i128_index(const vector<field_def>& fields);
bool is_str_index(const vector<field_def>& fields);
void guess_index_type(table_def& table, const struct_def s);
void guess_key_names(table_def& table, const struct_def s);
const table_def* find_table(const table_name& name);
const type_def* find_type(const type_name& new_type_name);
const action_def* find_action(const action_name& name);
const struct_def* find_struct(const type_name& name);
type_name resolve_type(const type_name& type);
bool is_one_filed_no_base(const string& type_name);
string decl_to_string(clang::Decl* d);
bool is_typedef(const clang::QualType& qt);
QualType add_typedef(const clang::QualType& qt, size_t recursion_depth);
bool is_vector(const clang::QualType& qt);
bool is_vector(const string& type_name);
string add_vector(const clang::QualType& qt, size_t recursion_depth);
bool is_struct(const clang::QualType& qt);
string add_struct(const clang::QualType& qt, string full_type_name, size_t recursion_depth);
string get_type_name(const clang::QualType& qt, bool no_namespace);
string add_type(const clang::QualType& tqt, size_t recursion_depth);
bool is_elaborated(const clang::QualType& qt);
bool is_struct_specialization(const clang::QualType& qt);
QualType get_vector_element_type(const clang::QualType& qt);
string get_vector_element_type(const string& type_name);
clang::QualType get_named_type_if_elaborated(const clang::QualType& qt);
const clang::RecordDecl::field_range get_struct_fields(const clang::QualType& qt);
clang::CXXRecordDecl::base_class_range get_struct_bases(const clang::QualType& qt);
};
struct abi_generator_astconsumer : public ASTConsumer {
abi_generator& abi_gen;
abi_generator_astconsumer(CompilerInstance& compiler_instance, abi_generator& abi_gen)
:abi_gen(abi_gen)
{
abi_gen.set_compiler_instance(compiler_instance);
}
void HandleTagDeclDefinition(TagDecl* tag_decl) override {
abi_gen.handle_tagdecl_definition(tag_decl);
}
};
struct find_eosio_abi_macro_action : public PreprocessOnlyAction {
string& contract;
vector<string>& actions;
const string& abi_context;
find_eosio_abi_macro_action(string& contract, vector<string>& actions, const string& abi_context
): contract(contract),
actions(actions), abi_context(abi_context) {
}
struct callback_handler : public PPCallbacks {
CompilerInstance& compiler_instance;
find_eosio_abi_macro_action& act;
callback_handler(CompilerInstance& compiler_instance, find_eosio_abi_macro_action& act)
: compiler_instance(compiler_instance), act(act) {}
string remove_namespace(const string& full_name) {
int i = full_name.size();
int on_spec = 0;
int colons = 0;
while( --i >= 0 ) {
if( full_name[i] == '>' ) {
++on_spec; colons=0;
} else if( full_name[i] == '<' ) {
--on_spec; colons=0;
} else if( full_name[i] == ':' && !on_spec) {
if (++colons == 2)
return full_name.substr(i+2);
} else {
colons = 0;
}
}
return full_name;
}
void MacroExpands (const Token &token, const MacroDefinition &md, SourceRange range, const MacroArgs *args) override {
auto* id = token.getIdentifierInfo();
if( id == nullptr ) return;
if( id->getName() != "EOSIO_ABI" ) return;
const auto& sm = compiler_instance.getSourceManager();
auto file_name = sm.getFilename(range.getBegin());
if ( !act.abi_context.empty() && !file_name.startswith(act.abi_context) ) {
return;
}
ABI_ASSERT( md.getMacroInfo()->getNumArgs() == 2 );
clang::SourceLocation b(range.getBegin()), _e(range.getEnd());
clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance.getLangOpts()));
auto macrostr = string(sm.getCharacterData(b), sm.getCharacterData(e)-sm.getCharacterData(b));
regex r(R"(EOSIO_ABI\s*\(\s*(.+?)\s*,((?:.+?)*)\s*\))");
smatch smatch;
auto res = regex_search(macrostr, smatch, r);
ABI_ASSERT( res );
act.contract = remove_namespace(smatch[1].str());
auto actions_str = smatch[2].str();
boost::trim(actions_str);
actions_str = actions_str.substr(1);
actions_str.pop_back();
boost::remove_erase_if(actions_str, boost::is_any_of(" ("));
boost::split(act.actions, actions_str, boost::is_any_of(")"));
}
};
void ExecuteAction() override {
getCompilerInstance().getPreprocessor().addPPCallbacks(
llvm::make_unique<callback_handler>(getCompilerInstance(), *this)
);
PreprocessOnlyAction::ExecuteAction();
};
};
class generate_abi_action : public ASTFrontendAction {
private:
set<string> parsed_templates;
abi_generator abi_gen;
public:
generate_abi_action(bool verbose, bool opt_sfs, string abi_context,
abi_def& output, const string& contract, const vector<string>& actions) {
ricardian_contracts rc( abi_context, contract, actions );
abi_gen.set_output(output);
abi_gen.set_verbose(verbose);
abi_gen.set_abi_context(abi_context);
abi_gen.set_target_contract(contract, actions);
abi_gen.set_ricardian_contracts( rc );
output.ricardian_clauses = rc.get_clauses();
if(opt_sfs)
abi_gen.enable_optimizaton(abi_generator::OPT_SINGLE_FIELD_STRUCT);
}
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& compiler_instance,
llvm::StringRef) override {
return llvm::make_unique<abi_generator_astconsumer>(compiler_instance, abi_gen);
}
};
} //ns eosio
#pragma pop_macro("N")
Subproject commit f3a63c1c04df957c0675b51d298851c71d6ccbe7
Subproject commit 1d6e6e4a0b334553658fe05cfa1e86081b6d0b4a
......@@ -50,7 +50,7 @@ add_library( eosio_chain
${HEADERS}
)
target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime
target_link_libraries( eosio_chain fc chainbase Logging IR WAST WASM Runtime
softfloat builtins wabt
)
target_include_directories( eosio_chain
......
......@@ -51,7 +51,7 @@ void apply_context::exec_one( action_trace& trace )
privileged = a.privileged;
auto native = control.find_apply_handler( receiver, act.account, act.name );
if( native ) {
if( trx_context.can_subjectively_fail && control.is_producing_block() ) {
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act.account, act.name );
}
......@@ -61,7 +61,7 @@ void apply_context::exec_one( action_trace& trace )
if( a.code.size() > 0
&& !(act.account == config::system_account_name && act.name == N( setcode ) &&
receiver == config::system_account_name) ) {
if( trx_context.can_subjectively_fail && control.is_producing_block() ) {
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act.account, act.name );
}
......@@ -205,6 +205,9 @@ void apply_context::execute_inline( action&& a ) {
EOS_ASSERT( code != nullptr, action_validate_exception,
"inline action's code account ${account} does not exist", ("account", a.account) );
bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block();
flat_set<account_name> actors;
for( const auto& auth : a.authorization ) {
auto* actor = control.db().find<account_object, by_name>(auth.actor);
EOS_ASSERT( actor != nullptr, action_validate_exception,
......@@ -212,6 +215,12 @@ void apply_context::execute_inline( action&& a ) {
EOS_ASSERT( control.get_authorization_manager().find_permission(auth) != nullptr, action_validate_exception,
"inline action's authorizations include a non-existent permission: ${permission}",
("permission", auth) );
if( enforce_actor_whitelist_blacklist )
actors.insert( auth.actor );
}
if( enforce_actor_whitelist_blacklist ) {
control.check_actor_list( actors );
}
// No need to check authorization if: replaying irreversible blocks; contract is privileged; or, contract is calling itself.
......@@ -249,7 +258,10 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" );
trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary)
trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary
control.validate_referenced_accounts( trx );
bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block()
&& !control.sender_avoids_whitelist_blacklist_enforcement( receiver );
trx_context.validate_referenced_accounts( trx, enforce_actor_whitelist_blacklist );
// Charge ahead of time for the additional net usage needed to retire the deferred transaction
// whether that be by successfully executing, soft failure, hard failure, or expiration.
......
......@@ -58,8 +58,6 @@ namespace eosio { namespace chain {
result.blockroot_merkle = blockroot_merkle;
result.blockroot_merkle.append( id );
auto block_mroot = result.blockroot_merkle.get_root();
result.active_schedule = active_schedule;
result.pending_schedule = pending_schedule;
result.dpos_proposed_irreversible_blocknum = dpos_proposed_irreversible_blocknum;
......@@ -143,7 +141,7 @@ namespace eosio { namespace chain {
*
* If the header specifies new_producers then apply them accordingly.
*/
block_header_state block_header_state::next( const signed_block_header& h, bool trust )const {
block_header_state block_header_state::next( const signed_block_header& h, bool skip_validate_signee )const {
EOS_ASSERT( h.timestamp != block_timestamp_type(), block_validate_exception, "", ("h",h) );
EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" );
......@@ -178,9 +176,8 @@ namespace eosio { namespace chain {
result.id = result.header.id();
// ASSUMPTION FROM controller_impl::apply_block = all untrusted blocks will have their signatures pre-validated here
if( !trust ) {
EOS_ASSERT( result.block_signing_key == result.signee(), wrong_signing_key, "block not signed by expected key",
("result.block_signing_key", result.block_signing_key)("signee", result.signee() ) );
if( !skip_validate_signee ) {
result.verify_signee( result.signee() );
}
return result;
......@@ -236,6 +233,11 @@ namespace eosio { namespace chain {
return fc::crypto::public_key( header.producer_signature, sig_digest(), true );
}
void block_header_state::verify_signee( const public_key_type& signee )const {
EOS_ASSERT( block_signing_key == signee, wrong_signing_key, "block not signed by expected key",
("block_signing_key", block_signing_key)( "signee", signee ) );
}
void block_header_state::add_confirmation( const header_confirmation& conf ) {
for( const auto& c : confirmations )
EOS_ASSERT( c.producer != conf.producer, producer_double_confirm, "block already confirmed by this producer" );
......
......@@ -10,9 +10,9 @@ namespace eosio { namespace chain {
static_cast<block_header&>(*block) = header;
}
block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool trust )
:block_header_state( prev.next( *b, trust )), block( move(b) )
{ }
block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee )
:block_header_state( prev.next( *b, skip_validate_signee )), block( move(b) )
{ }
......
此差异已折叠。
......@@ -57,7 +57,7 @@ void validate_authority_precondition( const apply_context& context, const author
}
}
if( context.control.is_producing_block() ) {
if( context.trx_context.enforce_whiteblacklist && context.control.is_producing_block() ) {
for( const auto& p : auth.keys ) {
context.control.check_key_list( p.key );
}
......@@ -282,7 +282,7 @@ void apply_eosio_deleteauth(apply_context& context) {
const auto& index = db.get_index<permission_link_index, by_permission_name>();
auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission));
EOS_ASSERT(range.first == range.second, action_validate_exception,
"Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.",
"Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.",
("code", string(range.first->code))("type", string(range.first->message_type)));
}
......
......@@ -123,7 +123,16 @@ namespace eosio { namespace chain {
}
}
block_state_ptr fork_database::add( block_state_ptr n ) {
block_state_ptr fork_database::add( const block_state_ptr& n, bool skip_validate_previous ) {
EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" );
EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" );
if( !skip_validate_previous ) {
auto prior = my->index.find( n->block->previous );
EOS_ASSERT( prior != my->index.end(), unlinkable_block_exception,
"unlinkable block", ("id", n->block->id())("previous", n->block->previous) );
}
auto inserted = my->index.insert(n);
EOS_ASSERT( inserted.second, fork_database_exception, "duplicate block added?" );
......@@ -139,7 +148,7 @@ namespace eosio { namespace chain {
return n;
}
block_state_ptr fork_database::add( signed_block_ptr b, bool trust ) {
block_state_ptr fork_database::add( signed_block_ptr b, bool skip_validate_signee ) {
EOS_ASSERT( b, fork_database_exception, "attempt to add null block" );
EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" );
......@@ -150,9 +159,9 @@ namespace eosio { namespace chain {
auto prior = by_id_idx.find( b->previous );
EOS_ASSERT( prior != by_id_idx.end(), unlinkable_block_exception, "unlinkable block", ("id", string(b->id()))("previous", string(b->previous)) );
auto result = std::make_shared<block_state>( **prior, move(b), trust );
auto result = std::make_shared<block_state>( **prior, move(b), skip_validate_signee );
EOS_ASSERT( result, fork_database_exception , "fail to add new block state" );
return add(result);
return add(result, true);
}
const block_state_ptr& fork_database::head()const { return my->head; }
......
......@@ -575,12 +575,6 @@ class apply_context {
void add_ram_usage( account_name account, int64_t ram_delta );
void finalize_trace( action_trace& trace, const fc::time_point& start );
private:
void validate_referenced_accounts( const transaction& t )const;
void validate_expiration( const transaction& t )const;
/// Fields:
public:
......
......@@ -7,8 +7,7 @@
#include <eosio/chain/types.hpp>
#include <eosio/chain/authority.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/utilities/parallel_markers.hpp>
#include <eosio/chain/parallel_markers.hpp>
#include <fc/scoped_exit.hpp>
......@@ -148,11 +147,11 @@ namespace detail {
bool all_keys_used() const { return boost::algorithm::all_of_equal(_used_keys, true); }
flat_set<public_key_type> used_keys() const {
auto range = utilities::filter_data_by_marker(provided_keys, _used_keys, true);
auto range = filter_data_by_marker(provided_keys, _used_keys, true);
return {range.begin(), range.end()};
}
flat_set<public_key_type> unused_keys() const {
auto range = utilities::filter_data_by_marker(provided_keys, _used_keys, false);
auto range = filter_data_by_marker(provided_keys, _used_keys, false);
return {range.begin(), range.end()};
}
......
#pragma once
#include <eosio/chain/block_header.hpp>
#include <eosio/chain/incremental_merkle.hpp>
#include <future>
namespace eosio { namespace chain {
......@@ -51,6 +52,7 @@ struct block_header_state {
digest_type sig_digest()const;
void sign( const std::function<signature_type(const digest_type&)>& signer );
public_key_type signee()const;
void verify_signee(const public_key_type& signee)const;
};
......
......@@ -12,8 +12,8 @@
namespace eosio { namespace chain {
struct block_state : public block_header_state {
block_state( const block_header_state& cur ):block_header_state(cur){}
block_state( const block_header_state& prev, signed_block_ptr b, bool trust = false );
explicit block_state( const block_header_state& cur ):block_header_state(cur){}
block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee );
block_state( const block_header_state& prev, block_timestamp_type when );
block_state() = default;
......
......@@ -60,10 +60,50 @@ struct chain_config {
<< "Max Inline Action Depth: " << c.max_inline_action_depth << ", "
<< "Max Authority Depth: " << c.max_authority_depth << "\n";
}
};
bool operator==(const chain_config& a, const chain_config& b);
inline bool operator!=(const chain_config& a, const chain_config& b) { return !(a == b); }
friend inline bool operator ==( const chain_config& lhs, const chain_config& rhs ) {
return std::tie( lhs.max_block_net_usage,
lhs.target_block_net_usage_pct,
lhs.max_transaction_net_usage,
lhs.base_per_transaction_net_usage,
lhs.net_usage_leeway,
lhs.context_free_discount_net_usage_num,
lhs.context_free_discount_net_usage_den,
lhs.max_block_cpu_usage,
lhs.target_block_cpu_usage_pct,
lhs.max_transaction_cpu_usage,
lhs.max_transaction_cpu_usage,
lhs.max_transaction_lifetime,
lhs.deferred_trx_expiration_window,
lhs.max_transaction_delay,
lhs.max_inline_action_size,
lhs.max_inline_action_depth,
lhs.max_authority_depth
)
==
std::tie( rhs.max_block_net_usage,
rhs.target_block_net_usage_pct,
rhs.max_transaction_net_usage,
rhs.base_per_transaction_net_usage,
rhs.net_usage_leeway,
rhs.context_free_discount_net_usage_num,
rhs.context_free_discount_net_usage_den,
rhs.max_block_cpu_usage,
rhs.target_block_cpu_usage_pct,
rhs.max_transaction_cpu_usage,
rhs.max_transaction_cpu_usage,
rhs.max_transaction_lifetime,
rhs.deferred_trx_expiration_window,
rhs.max_transaction_delay,
rhs.max_inline_action_size,
rhs.max_inline_action_depth,
rhs.max_authority_depth
);
};
friend inline bool operator !=( const chain_config& lhs, const chain_config& rhs ) { return !(lhs == rhs); }
};
} } // namespace eosio::chain
......
......@@ -79,6 +79,7 @@ const static uint32_t default_max_trx_delay = 45*24*3600; //
const static uint32_t default_max_inline_action_size = 4 * 1024; // 4 KB
const static uint16_t default_max_inline_action_depth = 4;
const static uint16_t default_max_auth_depth = 6;
const static uint16_t default_controller_thread_pool_size = 2;
const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024;
// Should be large enough to allow recovery from badly set blockchain parameters without a hard fork
......
......@@ -131,14 +131,14 @@ namespace eosio { namespace chain {
typedef secondary_index<key256_t,index256_object_type>::index_index index256_index;
struct soft_double_less {
bool operator()( const float64_t& lhs, const float64_t& rhs )const {
return f64_lt(lhs, rhs);
bool operator()( const float64_t& lhs, const float64_t& rhs ) const {
return f64_lt( lhs, rhs );
}
};
struct soft_long_double_less {
bool operator()( const float128_t lhs, const float128_t& rhs )const {
return f128_lt(lhs, rhs);
bool operator()( const float128_t& lhs, const float128_t& rhs ) const {
return f128_lt( lhs, rhs );
}
};
......@@ -147,6 +147,7 @@ namespace eosio { namespace chain {
*
* The software double implementation is using the Berkeley softfloat library (release 3).
*/
typedef secondary_index<float64_t,index_double_object_type,soft_double_less>::index_object index_double_object;
typedef secondary_index<float64_t,index_double_object_type,soft_double_less>::index_index index_double_index;
......@@ -158,6 +159,65 @@ namespace eosio { namespace chain {
typedef secondary_index<float128_t,index_long_double_object_type,soft_long_double_less>::index_object index_long_double_object;
typedef secondary_index<float128_t,index_long_double_object_type,soft_long_double_less>::index_index index_long_double_index;
template<typename T>
struct secondary_key_traits {
using value_type = std::enable_if_t<std::is_integral<T>::value, T>;
static_assert( std::numeric_limits<value_type>::is_specialized, "value_type does not have specialized numeric_limits" );
static constexpr value_type true_lowest() { return std::numeric_limits<value_type>::lowest(); }
static constexpr value_type true_highest() { return std::numeric_limits<value_type>::max(); }
};
template<size_t N>
struct secondary_key_traits<std::array<uint128_t, N>> {
private:
static constexpr uint128_t max_uint128 = (static_cast<uint128_t>(std::numeric_limits<uint64_t>::max()) << 64) | std::numeric_limits<uint64_t>::max();
static_assert( std::numeric_limits<uint128_t>::max() == max_uint128, "numeric_limits for uint128_t is not properly defined" );
public:
using value_type = std::array<uint128_t, N>;
static value_type true_lowest() {
value_type arr;
return arr;
}
static value_type true_highest() {
value_type arr;
for( auto& v : arr ) {
v = std::numeric_limits<uint128_t>::max();
}
return arr;
}
};
template<>
struct secondary_key_traits<float64_t> {
using value_type = float64_t;
static value_type true_lowest() {
return f64_negative_infinity();
}
static value_type true_highest() {
return f64_positive_infinity();
}
};
template<>
struct secondary_key_traits<float128_t> {
using value_type = float128_t;
static value_type true_lowest() {
return f128_negative_infinity();
}
static value_type true_highest() {
return f128_positive_infinity();
}
};
/**
* helper template to map from an index type to the best tag
* to use when traversing by table_id
......@@ -185,7 +245,7 @@ namespace config {
template<>
struct billable_size<table_id_object> {
static const uint64_t overhead = overhead_per_row_per_index_ram_bytes * 2; ///< overhead for 2x indices internal-key and code,scope,table
static const uint64_t value = 44 + overhead; ///< 36 bytes for constant size fields + overhead
static const uint64_t value = 44 + overhead; ///< 44 bytes for constant size fields + overhead
};
template<>
......
......@@ -50,6 +50,7 @@ namespace eosio { namespace chain {
public:
struct config {
flat_set<account_name> sender_bypass_whiteblacklist;
flat_set<account_name> actor_whitelist;
flat_set<account_name> actor_blacklist;
flat_set<account_name> contract_whitelist;
......@@ -62,6 +63,7 @@ namespace eosio { namespace chain {
uint64_t state_guard_size = chain::config::default_state_guard_size;
uint64_t reversible_cache_size = chain::config::default_reversible_cache_size;
uint64_t reversible_guard_size = chain::config::default_reversible_guard_size;
uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size;
bool read_only = false;
bool force_all_checks = false;
bool disable_replay_opts = false;
......@@ -89,7 +91,7 @@ namespace eosio { namespace chain {
~controller();
void add_indices();
void startup( const snapshot_reader_ptr& snapshot = nullptr );
void startup( std::function<bool()> shutdown, const snapshot_reader_ptr& snapshot = nullptr );
/**
* Starts a new pending block session upon which new transactions can
......@@ -139,13 +141,8 @@ namespace eosio { namespace chain {
void commit_block();
void pop_block();
void push_block( const signed_block_ptr& b, block_status s = block_status::complete );
/**
* Call this method when a producer confirmation is received, this might update
* the last bft irreversible block and/or cause a switch of forks
*/
void push_confirmation( const header_confirmation& c );
std::future<block_state_ptr> create_block_state_future( const signed_block_ptr& b );
void push_block( std::future<block_state_ptr>& block_state_future );
const chainbase::database& db()const;
......@@ -207,6 +204,8 @@ namespace eosio { namespace chain {
sha256 calculate_integrity_hash()const;
void write_snapshot( const snapshot_writer_ptr& snapshot )const;
bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const;
void check_actor_list( const flat_set<account_name>& actors )const;
void check_contract_list( account_name code )const;
void check_action_list( account_name code, action_name action )const;
void check_key_list( const public_key_type& key )const;
......@@ -219,7 +218,6 @@ namespace eosio { namespace chain {
bool is_resource_greylisted(const account_name &name) const;
const flat_set<account_name> &get_resource_greylist() const;
void validate_referenced_accounts( const transaction& t )const;
void validate_expiration( const transaction& t )const;
void validate_tapos( const transaction& t )const;
void validate_db_available_size() const;
......
......@@ -216,4 +216,3 @@ DataStream& operator >> ( DataStream& ds, float128_t& v ) {
fc::raw::unpack(ds, *reinterpret_cast<eosio::chain::uint128_t*>(&v));
return ds;
}
......@@ -439,8 +439,8 @@ namespace eosio { namespace chain {
3160007, "Invalid contract vm version" )
FC_DECLARE_DERIVED_EXCEPTION( set_exact_code, contract_exception,
3160008, "Contract is already running this version of code" )
FC_DECLARE_DERIVED_EXCEPTION( wast_file_not_found, contract_exception,
3160009, "No wast file found" )
FC_DECLARE_DERIVED_EXCEPTION( wasm_file_not_found, contract_exception,
3160009, "No wasm file found" )
FC_DECLARE_DERIVED_EXCEPTION( abi_file_not_found, contract_exception,
3160010, "No abi file found" )
......
......@@ -36,12 +36,12 @@ namespace eosio { namespace chain {
*/
void set( block_state_ptr s );
/** this method will attempt to append the block to an exsting
/** this method will attempt to append the block to an existing
* block_state and will return a pointer to the new block state or
* throw on error.
*/
block_state_ptr add( signed_block_ptr b, bool trust = false );
block_state_ptr add( block_state_ptr next_block );
block_state_ptr add( signed_block_ptr b, bool skip_validate_signee );
block_state_ptr add( const block_state_ptr& next_block, bool skip_validate_previous );
void remove( const block_id_type& id );
void add( const header_confirmation& c );
......
......@@ -51,6 +51,14 @@ struct genesis_state {
* This is the SHA256 serialization of the genesis_state.
*/
chain_id_type compute_chain_id() const;
friend inline bool operator==( const genesis_state& lhs, const genesis_state& rhs ) {
return std::tie( lhs.initial_configuration, lhs.initial_timestamp, lhs.initial_key )
== std::tie( rhs.initial_configuration, rhs.initial_timestamp, rhs.initial_key );
};
friend inline bool operator!=( const genesis_state& lhs, const genesis_state& rhs ) { return !(lhs == rhs); }
};
} } // namespace eosio::chain
......
......@@ -8,7 +8,7 @@
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
namespace eosio { namespace utilities {
namespace eosio { namespace chain {
/**
* @brief Return values in DataRange corresponding to matching Markers
......@@ -39,5 +39,5 @@ DataRange filter_data_by_marker(DataRange data, MarkerRange markers, const Marke
return {range.begin(), range.end()};
}
}} // namespace eosio::utilities
}} // namespace eosio::chain
......@@ -56,6 +56,8 @@ namespace eosio { namespace chain {
std::tuple<int64_t, int64_t, bool, bool> max_bandwidth_billed_accounts_can_pay( bool force_elastic_limits = false )const;
void validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const;
private:
friend struct controller_impl;
......@@ -95,7 +97,7 @@ namespace eosio { namespace chain {
fc::microseconds delay;
bool is_input = false;
bool apply_context_free = true;
bool can_subjectively_fail = true;
bool enforce_whiteblacklist = true;
fc::time_point deadline = fc::time_point::maximum();
fc::microseconds leeway = fc::microseconds(3000);
......
......@@ -4,8 +4,8 @@
*/
#pragma once
#include <eosio/chain/transaction.hpp>
#include <eosio/chain/block.hpp>
#include <eosio/chain/trace.hpp>
#include <eosio/chain/types.hpp>
#include <future>
namespace eosio { namespace chain {
......@@ -20,6 +20,7 @@ class transaction_metadata {
signed_transaction trx;
packed_transaction packed_trx;
optional<pair<chain_id_type, flat_set<public_key_type>>> signing_keys;
std::future<pair<chain_id_type,flat_set<public_key_type>>> signing_keys_future;
bool accepted = false;
bool implicit = false;
bool scheduled = false;
......@@ -39,8 +40,16 @@ class transaction_metadata {
}
const flat_set<public_key_type>& recover_keys( const chain_id_type& chain_id ) {
if( !signing_keys || signing_keys->first != chain_id ) // Unlikely for more than one chain_id to be used in one nodeos instance
signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id ) );
// Unlikely for more than one chain_id to be used in one nodeos instance
if( !signing_keys || signing_keys->first != chain_id ) {
if( signing_keys_future.valid() ) {
signing_keys = signing_keys_future.get();
if( signing_keys->first == chain_id ) {
return signing_keys->second;
}
}
signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id ));
}
return signing_keys->second;
}
......
......@@ -87,7 +87,7 @@ flat_set<public_key_type> transaction::get_signature_keys( const vector<signatur
using boost::adaptors::transformed;
constexpr size_t recovery_cache_size = 1000;
static recovery_cache_type recovery_cache;
static thread_local recovery_cache_type recovery_cache;
const digest_type digest = sig_digest(chain_id, cfd);
flat_set<public_key_type> recovered_pub_keys;
......
......@@ -26,7 +26,7 @@ namespace bacc = boost::accumulators;
struct deadline_timer_verify {
deadline_timer_verify() {
//keep longest first in list. You're effectively going to take test_intervals[0]*sizeof(test_intervals[0])
//time to do the the "calibration"
//time to do the the "calibration"
int test_intervals[] = {50000, 10000, 5000, 1000, 500, 100, 50, 10};
struct sigaction act;
......@@ -314,7 +314,7 @@ namespace bacc = boost::accumulators;
if (!control.skip_trx_checks()) {
control.validate_expiration(trx);
control.validate_tapos(trx);
control.validate_referenced_accounts(trx);
validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() );
}
init( initial_net_usage);
if (!skip_recording)
......@@ -615,5 +615,43 @@ namespace bacc = boost::accumulators;
}
} /// record_transaction
void transaction_context::validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const {
const auto& db = control.db();
const auto& auth_manager = control.get_authorization_manager();
for( const auto& a : trx.context_free_actions ) {
auto* code = db.find<account_object, by_name>(a.account);
EOS_ASSERT( code != nullptr, transaction_exception,
"action's code account '${account}' does not exist", ("account", a.account) );
EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
"context-free actions cannot have authorizations" );
}
flat_set<account_name> actors;
bool one_auth = false;
for( const auto& a : trx.actions ) {
auto* code = db.find<account_object, by_name>(a.account);
EOS_ASSERT( code != nullptr, transaction_exception,
"action's code account '${account}' does not exist", ("account", a.account) );
for( const auto& auth : a.authorization ) {
one_auth = true;
auto* actor = db.find<account_object, by_name>(auth.actor);
EOS_ASSERT( actor != nullptr, transaction_exception,
"action's authorizing actor '${account}' does not exist", ("account", auth.actor) );
EOS_ASSERT( auth_manager.find_permission(auth) != nullptr, transaction_exception,
"action's authorizations include a non-existent permission: {permission}",
("permission", auth) );
if( enforce_actor_whitelist_blacklist )
actors.insert( auth.actor );
}
}
EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
if( enforce_actor_whitelist_blacklist ) {
control.check_actor_list( actors );
}
}
} } /// eosio::chain
......@@ -237,8 +237,8 @@ class softfloat_api : public context_aware_api {
if (is_nan(b)) {
return bf;
}
if ( sign_bit(a) != sign_bit(b) ) {
return sign_bit(a) ? af : bf;
if ( f32_sign_bit(a) != f32_sign_bit(b) ) {
return f32_sign_bit(a) ? af : bf;
}
return f32_lt(a,b) ? af : bf;
}
......@@ -251,8 +251,8 @@ class softfloat_api : public context_aware_api {
if (is_nan(b)) {
return bf;
}
if ( sign_bit(a) != sign_bit(b) ) {
return sign_bit(a) ? bf : af;
if ( f32_sign_bit(a) != f32_sign_bit(b) ) {
return f32_sign_bit(a) ? bf : af;
}
return f32_lt( a, b ) ? bf : af;
}
......@@ -404,8 +404,8 @@ class softfloat_api : public context_aware_api {
return af;
if (is_nan(b))
return bf;
if (sign_bit(a) != sign_bit(b))
return sign_bit(a) ? af : bf;
if (f64_sign_bit(a) != f64_sign_bit(b))
return f64_sign_bit(a) ? af : bf;
return f64_lt( a, b ) ? af : bf;
}
double _eosio_f64_max( double af, double bf ) {
......@@ -415,8 +415,8 @@ class softfloat_api : public context_aware_api {
return af;
if (is_nan(b))
return bf;
if (sign_bit(a) != sign_bit(b))
return sign_bit(a) ? bf : af;
if (f64_sign_bit(a) != f64_sign_bit(b))
return f64_sign_bit(a) ? bf : af;
return f64_lt( a, b ) ? bf : af;
}
double _eosio_f64_copysign( double af, double bf ) {
......@@ -650,32 +650,17 @@ class softfloat_api : public context_aware_api {
}
static bool is_nan( const float32_t f ) {
return ((f.v & 0x7FFFFFFF) > 0x7F800000);
return f32_is_nan( f );
}
static bool is_nan( const float64_t f ) {
return ((f.v & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000);
return f64_is_nan( f );
}
static bool is_nan( const float128_t& f ) {
return (((~(f.v[1]) & uint64_t( 0x7FFF000000000000 )) == 0) && (f.v[0] || ((f.v[1]) & uint64_t( 0x0000FFFFFFFFFFFF ))));
}
static float32_t to_softfloat32( float f ) {
return *reinterpret_cast<float32_t*>(&f);
}
static float64_t to_softfloat64( double d ) {
return *reinterpret_cast<float64_t*>(&d);
}
static float from_softfloat32( float32_t f ) {
return *reinterpret_cast<float*>(&f);
}
static double from_softfloat64( float64_t d ) {
return *reinterpret_cast<double*>(&d);
return f128_is_nan( f );
}
static constexpr uint32_t inv_float_eps = 0x4B000000;
static constexpr uint64_t inv_double_eps = 0x4330000000000000;
static bool sign_bit( float32_t f ) { return f.v >> 31; }
static bool sign_bit( float64_t f ) { return f.v >> 63; }
};
class producer_api : public context_aware_api {
......@@ -922,7 +907,6 @@ public:
:context_aware_api(ctx,true){}
void abort() {
edump(("abort() called"));
EOS_ASSERT( false, abort_called, "abort() called");
}
......@@ -930,7 +914,6 @@ public:
void eosio_assert( bool condition, null_terminated_ptr msg ) {
if( BOOST_UNLIKELY( !condition ) ) {
std::string message( msg );
edump((message));
EOS_THROW( eosio_assert_message_exception, "assertion failure with message: ${s}", ("s",message) );
}
}
......@@ -938,14 +921,12 @@ public:
void eosio_assert_message( bool condition, array_ptr<const char> msg, size_t msg_len ) {
if( BOOST_UNLIKELY( !condition ) ) {
std::string message( msg, msg_len );
edump((message));
EOS_THROW( eosio_assert_message_exception, "assertion failure with message: ${s}", ("s",message) );
}
}
void eosio_assert_code( bool condition, uint64_t error_code ) {
if( BOOST_UNLIKELY( !condition ) ) {
edump((error_code));
EOS_THROW( eosio_assert_code_exception,
"assertion failure with error code: ${error_code}", ("error_code", error_code) );
}
......@@ -1515,18 +1496,18 @@ class compiler_builtins : public context_aware_api {
// conversion long double
void __extendsftf2( float128_t& ret, float f ) {
ret = f32_to_f128( softfloat_api::to_softfloat32(f) );
ret = f32_to_f128( to_softfloat32(f) );
}
void __extenddftf2( float128_t& ret, double d ) {
ret = f64_to_f128( softfloat_api::to_softfloat64(d) );
ret = f64_to_f128( to_softfloat64(d) );
}
double __trunctfdf2( uint64_t l, uint64_t h ) {
float128_t f = {{ l, h }};
return softfloat_api::from_softfloat64(f128_to_f64( f ));
return from_softfloat64(f128_to_f64( f ));
}
float __trunctfsf2( uint64_t l, uint64_t h ) {
float128_t f = {{ l, h }};
return softfloat_api::from_softfloat32(f128_to_f32( f ));
return from_softfloat32(f128_to_f32( f ));
}
int32_t __fixtfsi( uint64_t l, uint64_t h ) {
float128_t f = {{ l, h }};
......@@ -1553,19 +1534,19 @@ class compiler_builtins : public context_aware_api {
ret = ___fixunstfti( f );
}
void __fixsfti( __int128& ret, float a ) {
ret = ___fixsfti( softfloat_api::to_softfloat32(a).v );
ret = ___fixsfti( to_softfloat32(a).v );
}
void __fixdfti( __int128& ret, double a ) {
ret = ___fixdfti( softfloat_api::to_softfloat64(a).v );
ret = ___fixdfti( to_softfloat64(a).v );
}
void __fixunssfti( unsigned __int128& ret, float a ) {
ret = ___fixunssfti( softfloat_api::to_softfloat32(a).v );
ret = ___fixunssfti( to_softfloat32(a).v );
}
void __fixunsdfti( unsigned __int128& ret, double a ) {
ret = ___fixunsdfti( softfloat_api::to_softfloat64(a).v );
ret = ___fixunsdfti( to_softfloat64(a).v );
}
double __floatsidf( int32_t i ) {
return softfloat_api::from_softfloat64(i32_to_f64(i));
return from_softfloat64(i32_to_f64(i));
}
void __floatsitf( float128_t& ret, int32_t i ) {
ret = i32_to_f128(i);
......
Subproject commit 9adee183df3ce4170d1f362c96d960132bd77ed9
Subproject commit a8613d3786cddfcc336808d2b9b7df655e6cc6d1
Subproject commit 9942875eb704369db297eb289aa4e9912bddcfb8
Subproject commit 203b6df7dedc5bae1b2a7b1b23562335a6344578
......@@ -7,7 +7,7 @@ add_library( eosio_testing
${HEADERS}
)
target_link_libraries( eosio_testing eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime )
target_link_libraries( eosio_testing eosio_chain fc chainbase Logging IR WAST WASM Runtime )
target_include_directories( eosio_testing
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include"
......
......@@ -91,6 +91,7 @@ namespace eosio { namespace testing {
virtual signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0/*skip_missed_block_penalty*/ ) = 0;
virtual signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0/*skip_missed_block_penalty*/ ) = 0;
virtual signed_block_ptr finish_block() = 0;
void produce_blocks( uint32_t n = 1, bool empty = false );
void produce_blocks_until_end_of_round();
void produce_blocks_for_n_rounds(const uint32_t num_of_rounds = 1);
......@@ -271,6 +272,7 @@ namespace eosio { namespace testing {
protected:
signed_block_ptr _produce_block( fc::microseconds skip_time, bool skip_pending_trxs = false, uint32_t skip_flag = 0 );
void _start_block(fc::time_point block_time);
signed_block_ptr _finish_block();
// Fields:
protected:
......@@ -304,6 +306,10 @@ namespace eosio { namespace testing {
return _produce_block(skip_time, true, skip_flag);
}
signed_block_ptr finish_block()override {
return _finish_block();
}
bool validate() { return true; }
};
......@@ -351,7 +357,7 @@ namespace eosio { namespace testing {
validating_node = std::make_unique<controller>(vcfg);
validating_node->add_indices();
validating_node->startup();
validating_node->startup( []() { return false; } );
init(true);
}
......@@ -366,14 +372,15 @@ namespace eosio { namespace testing {
validating_node = std::make_unique<controller>(vcfg);
validating_node->add_indices();
validating_node->startup();
validating_node->startup( []() { return false; } );
init(config);
}
signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0 /*skip_missed_block_penalty*/ )override {
auto sb = _produce_block(skip_time, false, skip_flag | 2);
validating_node->push_block( sb );
auto bs = validating_node->create_block_state_future( sb );
validating_node->push_block( bs );
return sb;
}
......@@ -383,19 +390,23 @@ namespace eosio { namespace testing {
}
void validate_push_block(const signed_block_ptr& sb) {
validating_node->push_block( sb );
auto bs = validating_node->create_block_state_future( sb );
validating_node->push_block( bs );
}
signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0 /*skip_missed_block_penalty*/ )override {
control->abort_block();
auto sb = _produce_block(skip_time, true, skip_flag | 2);
validating_node->push_block( sb );
auto bs = validating_node->create_block_state_future( sb );
validating_node->push_block( bs );
return sb;
}
signed_block_ptr finish_block()override {
return _finish_block();
}
bool validate() {
......@@ -411,7 +422,7 @@ namespace eosio { namespace testing {
validating_node.reset();
validating_node = std::make_unique<controller>(vcfg);
validating_node->add_indices();
validating_node->startup();
validating_node->startup( []() { return false; } );
return ok;
}
......
......@@ -124,7 +124,7 @@ namespace eosio { namespace testing {
void base_tester::open( const snapshot_reader_ptr& snapshot) {
control.reset( new controller(cfg) );
control->add_indices();
control->startup(snapshot);
control->startup( []() { return false; }, snapshot);
chain_transactions.clear();
control->accepted_block.connect([this]( const block_state_ptr& block_state ){
FC_ASSERT( block_state->block );
......@@ -141,8 +141,9 @@ namespace eosio { namespace testing {
}
signed_block_ptr base_tester::push_block(signed_block_ptr b) {
auto bs = control->create_block_state_future(b);
control->abort_block();
control->push_block(b);
control->push_block(bs);
auto itr = last_produced_block.find(b->producer);
if (itr == last_produced_block.end() || block_header::num_from_id(b->id()) > block_header::num_from_id(itr->second)) {
......@@ -161,17 +162,6 @@ namespace eosio { namespace testing {
_start_block( next_time );
}
auto producer = control->head_block_state()->get_scheduled_producer(next_time);
private_key_type priv_key;
// Check if signing private key exist in the list
auto private_key_itr = block_signing_private_keys.find( producer.block_signing_key );
if( private_key_itr == block_signing_private_keys.end() ) {
// If it's not found, default to active k1 key
priv_key = get_private_key( producer.producer_name, "active" );
} else {
priv_key = private_key_itr->second;
}
if( !skip_pending_trxs ) {
auto unapplied_trxs = control->get_unapplied_transactions();
for (const auto& trx : unapplied_trxs ) {
......@@ -192,18 +182,10 @@ namespace eosio { namespace testing {
}
}
control->finalize_block();
control->sign_block( [&]( digest_type d ) {
return priv_key.sign(d);
});
control->commit_block();
last_produced_block[control->head_block_state()->header.producer] = control->head_block_state()->id;
auto head_block = _finish_block();
_start_block( next_time + fc::microseconds(config::block_interval_us));
return control->head_block_state()->block;
return head_block;
}
void base_tester::_start_block(fc::time_point block_time) {
......@@ -220,6 +202,30 @@ namespace eosio { namespace testing {
control->start_block( block_time, head_block_number - last_produced_block_num );
}
signed_block_ptr base_tester::_finish_block() {
FC_ASSERT( control->pending_block_state(), "must first start a block before it can be finished" );
auto producer = control->head_block_state()->get_scheduled_producer( control->pending_block_time() );
private_key_type priv_key;
// Check if signing private key exist in the list
auto private_key_itr = block_signing_private_keys.find( producer.block_signing_key );
if( private_key_itr == block_signing_private_keys.end() ) {
// If it's not found, default to active k1 key
priv_key = get_private_key( producer.producer_name, "active" );
} else {
priv_key = private_key_itr->second;
}
control->finalize_block();
control->sign_block( [&]( digest_type d ) {
return priv_key.sign(d);
});
control->commit_block();
last_produced_block[control->head_block_state()->header.producer] = control->head_block_state()->id;
return control->head_block_state()->block;
}
void base_tester::produce_blocks( uint32_t n, bool empty ) {
if( empty ) {
......@@ -795,8 +801,9 @@ namespace eosio { namespace testing {
for( int i = 1; i <= a.control->head_block_num(); ++i ) {
auto block = a.control->fetch_block_by_number(i);
if( block ) { //&& !b.control->is_known_block(block->id()) ) {
auto bs = b.control->create_block_state_future( block );
b.control->abort_block();
b.control->push_block(block); //, eosio::chain::validation_steps::created_block);
b.control->push_block(bs); //, eosio::chain::validation_steps::created_block);
}
}
};
......
#list( APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/libraries/fc/GitVersionGen" )
#include( GetGitRevisionDescription )
#get_git_head_revision(GIT_REFSPEC EOS_GIT_REVISION_SHA)
#get_git_unix_timestamp(EOS_GIT_REVISION_UNIX_TIMESTAMP)
#git_describe(EOS_GIT_REVISION_DESCRIPTION --tags)
if(NOT EOS_GIT_REVISION_DESCRIPTION)
set(EOS_GIT_REVISION_DESCRIPTION "unknown")
endif(NOT EOS_GIT_REVISION_DESCRIPTION)
file(GLOB HEADERS "include/eosio/utilities/*.hpp")
set(sources
key_conversion.cpp
string_escape.cpp
tempdir.cpp
words.cpp
${HEADERS})
#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/git_revision.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp" @ONLY)
#list(APPEND sources "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp")
add_library( eos_utilities
${sources}
${HEADERS} )
target_link_libraries( eos_utilities fc WAST WASM )
target_include_directories( eos_utilities
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" )
if (USE_PCH)
set_target_properties(eos_utilities PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
cotire(eos_utilities)
endif(USE_PCH)
#include <stdint.h>
#include <eos/utilities/git_revision.hpp>
#define EOS_GIT_REVISION_SHA "@EOS_GIT_REVISION_SHA@"
#define EOS_GIT_REVISION_UNIX_TIMESTAMP @EOS_GIT_REVISION_UNIX_TIMESTAMP@
#define EOS_GIT_REVISION_DESCRIPTION "@EOS_GIT_REVISION_DESCRIPTION@"
namespace eosio { namespace utilities {
const char* const git_revision_sha = EOS_GIT_REVISION_SHA;
const uint32_t git_revision_unix_timestamp = EOS_GIT_REVISION_UNIX_TIMESTAMP;
const char* const git_revision_description = EOS_GIT_REVISION_DESCRIPTION;
} } // end namespace eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*
*/
#pragma once
#ifndef COMMON_HPP
#define COMMON_HPP
namespace eosio { namespace utilities { namespace common {
template<typename I>
std::string itoh(I n, size_t hlen = sizeof(I)<<1) {
static const char* digits = "0123456789abcdef";
std::string r(hlen, '0');
for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4)
r[i] = digits[(n>>j) & 0x0f];
return r;
}
}}}
#endif // COMMON_HPP
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <stdint.h>
namespace eosio { namespace utilities {
extern const char* const git_revision_sha;
extern const uint32_t git_revision_unix_timestamp;
extern const char* const git_revision_description;
} } // end namespace eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <string>
#include <fc/crypto/elliptic.hpp>
#include <fc/optional.hpp>
namespace eosio { namespace utilities {
std::string key_to_wif(const fc::sha256& private_secret );
std::string key_to_wif(const fc::ecc::private_key& key);
fc::optional<fc::ecc::private_key> wif_to_key( const std::string& wif_key );
} } // end namespace eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
namespace eosio { namespace utilities {
template<size_t BlockSize=16, char PaddingChar=' '>
class padding_ostream : public fc::buffered_ostream {
public:
padding_ostream( fc::ostream_ptr o, size_t bufsize = 4096 ) : buffered_ostream(o, bufsize) {}
virtual ~padding_ostream() {}
virtual size_t writesome( const char* buffer, size_t len ) {
auto out = buffered_ostream::writesome(buffer, len);
bytes_out += out;
bytes_out %= BlockSize;
return out;
}
virtual size_t writesome( const std::shared_ptr<const char>& buf, size_t len, size_t offset ) {
auto out = buffered_ostream::writesome(buf, len, offset);
bytes_out += out;
bytes_out %= BlockSize;
return out;
}
virtual void flush() {
static const char pad = PaddingChar;
while( bytes_out % BlockSize )
writesome(&pad, 1);
buffered_ostream::flush();
}
private:
size_t bytes_out = 0;
};
} } //eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#ifndef RAND_HPP
#define RAND_HPP 1
#include <algorithm>
namespace eosio { namespace utilities { namespace rand {
/// High performance random generator
/// http://xorshift.di.unimi.it/
class random {
private:
uint64_t seed;
public:
random(uint64_t seed) {
this->seed = seed;
}
uint64_t next() {
uint64_t z = (seed += UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
return z ^ (z >> 31);
}
template <typename Range>
void shuffle(Range&& range) {
int idx_count = range.size();
for (auto idx = range.rbegin(); idx != range.rend() - 1; ++idx , --idx_count) {
std::swap(range.at(next() % idx_count), *idx);
}
}
};
} } } //eosio::utilities::rand
#endif // RAND_HPP
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <string>
namespace eosio { namespace utilities {
std::string escape_string_for_c_source_code(const std::string& input);
} } // end namespace eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <cstdlib>
#include <fc/filesystem.hpp>
namespace eosio { namespace utilities {
fc::path temp_directory_path();
} } // eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
namespace eosio { namespace words {
typedef const char* const_char_ptr;
extern const const_char_ptr word_list[];
extern const uint32_t word_list_size;
} }
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/utilities/key_conversion.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/variant.hpp>
namespace eosio { namespace utilities {
std::string key_to_wif(const fc::sha256& secret )
{
const size_t size_of_data_to_hash = sizeof(secret) + 1;
const size_t size_of_hash_bytes = 4;
char data[size_of_data_to_hash + size_of_hash_bytes];
data[0] = (char)0x80;
memcpy(&data[1], (char*)&secret, sizeof(secret));
fc::sha256 digest = fc::sha256::hash(data, size_of_data_to_hash);
digest = fc::sha256::hash(digest);
memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes);
return fc::to_base58(data, sizeof(data));
}
std::string key_to_wif(const fc::ecc::private_key& key)
{
return key_to_wif( key.get_secret() );
}
fc::optional<fc::ecc::private_key> wif_to_key( const std::string& wif_key )
{
std::vector<char> wif_bytes;
try
{
wif_bytes = fc::from_base58(wif_key);
}
catch (const fc::parse_error_exception&)
{
return fc::optional<fc::ecc::private_key>();
}
if (wif_bytes.size() < 5)
return fc::optional<fc::ecc::private_key>();
std::vector<char> key_bytes(wif_bytes.begin() + 1, wif_bytes.end() - 4);
fc::ecc::private_key key = fc::variant(key_bytes).as<fc::ecc::private_key>();
fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4);
fc::sha256 check2 = fc::sha256::hash(check);
if( memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ||
memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 )
return key;
return fc::optional<fc::ecc::private_key>();
}
} } // end namespace eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/utilities/string_escape.hpp>
#include <sstream>
namespace eosio { namespace utilities {
std::string escape_string_for_c_source_code(const std::string& input)
{
std::ostringstream escaped_string;
escaped_string << "\"";
for (unsigned i = 0; i < input.size(); ++i)
{
switch (input[i])
{
case '\a':
escaped_string << "\\a";
break;
case '\b':
escaped_string << "\\b";
break;
case '\t':
escaped_string << "\\t";
break;
case '\n':
escaped_string << "\\n";
break;
case '\v':
escaped_string << "\\v";
break;
case '\f':
escaped_string << "\\f";
break;
case '\r':
escaped_string << "\\r";
break;
case '\\':
escaped_string << "\\\\";
break;
case '\"':
escaped_string << "\\\"";
break;
default:
escaped_string << input[i];
}
}
escaped_string << "\"";
return escaped_string.str();
}
} } // end namespace eosio::utilities
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/utilities/tempdir.hpp>
#include <cstdlib>
namespace eosio { namespace utilities {
fc::path temp_directory_path()
{
const char* eos_tempdir = getenv("EOS_TEMPDIR");
if( eos_tempdir != nullptr )
return fc::path( eos_tempdir );
return fc::temp_directory_path() / "eos-tmp";
}
} } // eosio::utilities
此差异已折叠。
Subproject commit 2f5382661f7bf77cf7a70dcf0543a44fd5025910
Subproject commit bf353aa719c88b7152ee09e7f877a507cb7df27b
......@@ -9,6 +9,7 @@ add_subdirectory(producer_plugin)
add_subdirectory(producer_api_plugin)
add_subdirectory(history_plugin)
add_subdirectory(history_api_plugin)
add_subdirectory(state_history_plugin)
add_subdirectory(wallet_plugin)
add_subdirectory(wallet_api_plugin)
......
......@@ -306,7 +306,7 @@ namespace eosio {
int next_session_id()const {
static int session_count = 0;
static std::atomic<int> session_count(0);
return ++session_count;
}
......@@ -788,7 +788,7 @@ namespace eosio {
/// if something changed, the next block doesn't link to the last
/// block we sent, local chain must have switched forks
if( nextblock->previous != _last_sent_block_id ) {
if( nextblock->previous != _last_sent_block_id && _last_sent_block_id != block_id_type() ) {
if( !is_known_by_peer( nextblock->previous ) ) {
_last_sent_block_id = _local_lib_id;
_last_sent_block_num = _local_lib;
......@@ -1041,26 +1041,7 @@ namespace eosio {
return false;
}
void on( const packed_transaction_ptr& p ) {
peer_ilog(this, "received packed_transaction_ptr");
if (!p) {
peer_elog(this, "bad packed_transaction_ptr : null pointer");
EOS_THROW(transaction_exception, "bad transaction");
}
if( app().get_plugin<chain_plugin>().chain().get_read_mode() == chain::db_read_mode::READ_ONLY )
return;
// ilog( "recv trx ${n}", ("n", id) );
if( p->expiration() < fc::time_point::now() ) return;
// get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state
const auto& id = p->get_uncached_id();
if( mark_transaction_known_by_peer( id ) )
return;
app().get_channel<incoming::channels::transaction>().publish(p);
}
void on( const packed_transaction_ptr& p );
void on_write( boost::system::error_code ec, std::size_t bytes_transferred ) {
boost::ignore_unused(bytes_transferred);
......@@ -1402,8 +1383,10 @@ namespace eosio {
if( app().get_plugin<chain_plugin>().chain().get_read_mode() == chain::db_read_mode::READ_ONLY ) {
my->_request_trx = false;
ilog( "setting bnet-no-trx to true since in read-only mode" );
if (my->_request_trx) {
my->_request_trx = false;
ilog( "forced bnet-no-trx to true since in read-only mode" );
}
}
const auto address = boost::asio::ip::make_address( my->_bnet_endpoint_address );
......@@ -1557,4 +1540,24 @@ namespace eosio {
}
void session::on( const packed_transaction_ptr& p ) {
peer_ilog(this, "received packed_transaction_ptr");
if (!p) {
peer_elog(this, "bad packed_transaction_ptr : null pointer");
EOS_THROW(transaction_exception, "bad transaction");
}
if( !_net_plugin->_request_trx )
return;
// ilog( "recv trx ${n}", ("n", id) );
if( p->expiration() < fc::time_point::now() ) return;
// get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state
const auto& id = p->get_uncached_id();
if( mark_transaction_known_by_peer( id ) )
return;
app().get_channel<incoming::channels::transaction>().publish(p);
}
} /// namespace eosio
......@@ -18,10 +18,6 @@
#include <eosio/chain/eosio_contract.hpp>
#include <eosio/utilities/key_conversion.hpp>
#include <eosio/utilities/common.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <boost/signals2/connection.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
......@@ -222,6 +218,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
("chain-state-db-guard-size-mb", bpo::value<uint64_t>()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).")
("reversible-blocks-db-size-mb", bpo::value<uint64_t>()->default_value(config::default_reversible_cache_size / (1024 * 1024)), "Maximum size (in MiB) of the reversible blocks database")
("reversible-blocks-db-guard-size-mb", bpo::value<uint64_t>()->default_value(config::default_reversible_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the reverseible blocks database drops below this size (in MiB).")
("chain-threads", bpo::value<uint16_t>()->default_value(config::default_controller_thread_pool_size),
"Number of worker threads in controller thread pool")
("contracts-console", bpo::bool_switch()->default_value(false),
"print contract's output to console")
("actor-whitelist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
......@@ -236,6 +234,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
"Action (in the form code::action) added to action blacklist (may specify multiple times)")
("key-blacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
"Public key added to blacklist of keys that should not be included in authorities (may specify multiple times)")
("sender-bypass-whiteblacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
"Deferred transactions sent by accounts in this list do not have any of the subjective whitelist/blacklist checks applied to them (may specify multiple times)")
("read-mode", boost::program_options::value<eosio::chain::db_read_mode>()->default_value(eosio::chain::db_read_mode::SPECULATIVE),
"Database read mode (\"speculative\", \"head\", or \"read-only\").\n"// or \"irreversible\").\n"
"In \"speculative\" mode database contains changes done up to the head block plus changes made by transactions not yet included to the blockchain.\n"
......@@ -343,6 +343,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
my->chain_config = controller::config();
LOAD_VALUE_SET( options, "sender-bypass-whiteblacklist", my->chain_config->sender_bypass_whiteblacklist );
LOAD_VALUE_SET( options, "actor-whitelist", my->chain_config->actor_whitelist );
LOAD_VALUE_SET( options, "actor-blacklist", my->chain_config->actor_blacklist );
LOAD_VALUE_SET( options, "contract-whitelist", my->chain_config->contract_whitelist );
......@@ -419,6 +420,12 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
if( options.count( "reversible-blocks-db-guard-size-mb" ))
my->chain_config->reversible_guard_size = options.at( "reversible-blocks-db-guard-size-mb" ).as<uint64_t>() * 1024 * 1024;
if( options.count( "chain-threads" )) {
my->chain_config->thread_pool_size = options.at( "chain-threads" ).as<uint16_t>();
EOS_ASSERT( my->chain_config->thread_pool_size > 0, plugin_config_exception,
"chain-threads ${num} must be greater than 0", ("num", my->chain_config->thread_pool_size) );
}
if( my->wasm_runtime )
my->chain_config->wasm_runtime = *my->wasm_runtime;
......@@ -565,12 +572,17 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
}
} else {
if( options.count( "genesis-json" )) {
EOS_ASSERT( !fc::exists( my->blocks_dir / "blocks.log" ),
plugin_config_exception,
"Genesis state can only be set on a fresh blockchain." );
bfs::path genesis_file;
bool genesis_timestamp_specified = false;
fc::optional<genesis_state> existing_genesis;
auto genesis_file = options.at( "genesis-json" ).as<bfs::path>();
if( fc::exists( my->blocks_dir / "blocks.log" ) ) {
my->chain_config->genesis = block_log::extract_genesis_state( my->blocks_dir );
existing_genesis = my->chain_config->genesis;
}
if( options.count( "genesis-json" )) {
genesis_file = options.at( "genesis-json" ).as<bfs::path>();
if( genesis_file.is_relative()) {
genesis_file = bfs::current_path() / genesis_file;
}
......@@ -581,28 +593,32 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
("genesis", genesis_file.generic_string()));
my->chain_config->genesis = fc::json::from_file( genesis_file ).as<genesis_state>();
}
ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string()));
if( options.count( "genesis-timestamp" ) ) {
my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( options.at( "genesis-timestamp" ).as<string>() );
genesis_timestamp_specified = true;
}
if( options.count( "genesis-timestamp" )) {
my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp(
options.at( "genesis-timestamp" ).as<string>());
if( !existing_genesis ) {
if( !genesis_file.empty() ) {
if( genesis_timestamp_specified ) {
ilog( "Using genesis state provided in '${genesis}' but with adjusted genesis timestamp",
("genesis", genesis_file.generic_string()) );
} else {
ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string()));
}
wlog( "Starting up fresh blockchain with provided genesis state." );
} else if( genesis_timestamp_specified ) {
wlog( "Starting up fresh blockchain with default genesis state but with adjusted genesis timestamp." );
} else {
wlog( "Starting up fresh blockchain with default genesis state." );
}
wlog( "Starting up fresh blockchain with provided genesis state." );
} else if( options.count( "genesis-timestamp" )) {
EOS_ASSERT( !fc::exists( my->blocks_dir / "blocks.log" ),
plugin_config_exception,
"Genesis state can only be set on a fresh blockchain." );
my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp(
options.at( "genesis-timestamp" ).as<string>());
wlog( "Starting up fresh blockchain with default genesis state but with adjusted genesis timestamp." );
} else if( fc::is_regular_file( my->blocks_dir / "blocks.log" )) {
my->chain_config->genesis = block_log::extract_genesis_state( my->blocks_dir );
} else {
wlog( "Starting up fresh blockchain with default genesis state." );
EOS_ASSERT( my->chain_config->genesis == *existing_genesis, plugin_config_exception,
"Genesis state provided via command line arguments does not match the existing genesis state in blocks.log. "
"It is not necessary to provide genesis state arguments when a blocks.log file already exists."
);
}
}
......@@ -688,13 +704,14 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
void chain_plugin::plugin_startup()
{ try {
try {
auto shutdown = [](){ return app().is_quiting(); };
if (my->snapshot_path) {
auto infile = std::ifstream(my->snapshot_path->generic_string(), (std::ios::in | std::ios::binary));
auto reader = std::make_shared<istream_snapshot_reader>(infile);
my->chain->startup(reader);
my->chain->startup(shutdown, reader);
infile.close();
} else {
my->chain->startup();
my->chain->startup(shutdown);
}
} catch (const database_guard_exception& e) {
log_guard_exception(e);
......@@ -734,10 +751,6 @@ void chain_apis::read_write::validate() const {
EOS_ASSERT( db.get_read_mode() != chain::db_read_mode::READ_ONLY, missing_chain_api_plugin_exception, "Not allowed, node in read-only mode" );
}
chain_apis::read_write chain_plugin::get_read_write_api() {
return chain_apis::read_write(chain(), get_abi_serializer_max_time());
}
void chain_plugin::accept_block(const signed_block_ptr& block ) {
my->incoming_block_sync_method(block);
}
......@@ -992,10 +1005,19 @@ namespace chain_apis {
const string read_only::KEYi64 = "i64";
template<typename I>
std::string itoh(I n, size_t hlen = sizeof(I)<<1) {
static const char* digits = "0123456789abcdef";
std::string r(hlen, '0');
for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4)
r[i] = digits[(n>>j) & 0x0f];
return r;
}
read_only::get_info_results read_only::get_info(const read_only::get_info_params&) const {
const auto& rm = db.get_resource_limits_manager();
return {
eosio::utilities::common::itoh(static_cast<uint32_t>(app().version())),
itoh(static_cast<uint32_t>(app().version())),
db.get_chain_id(),
db.fork_db_head_block_num(),
db.last_irreversible_block_num(),
......@@ -1088,6 +1110,19 @@ uint64_t convert_to_type(const string& str, const string& desc) {
}
}
template<>
double convert_to_type(const string& str, const string& desc) {
double val{};
try {
val = fc::variant(str).as<double>();
} FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} string '${str}' to key type.", ("desc", desc)("str",str) )
EOS_ASSERT( !std::isnan(val), chain::contract_table_query_exception,
"Converted ${desc} string '${str}' to NaN which is not a permitted value for the key type", ("desc", desc)("str",str) );
return val;
}
abi_def get_abi( const controller& db, const name& account ) {
const auto &d = db.db();
const account_object *code_accnt = d.find<account_object, by_name>(account);
......@@ -1166,51 +1201,57 @@ read_only::get_table_rows_result read_only::get_table_rows( const read_only::get
}
read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_only::get_table_by_scope_params& p )const {
read_only::get_table_by_scope_result result;
const auto& d = db.db();
const auto& idx = d.get_index<chain::table_id_multi_index, chain::by_code_scope_table>();
decltype(idx.lower_bound(boost::make_tuple(0, 0, 0))) lower;
decltype(idx.upper_bound(boost::make_tuple(0, 0, 0))) upper;
auto lower_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits<uint64_t>::lowest(), p.table.value );
auto upper_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits<uint64_t>::max(),
(p.table.empty() ? std::numeric_limits<uint64_t>::max() : p.table.value) );
if (p.lower_bound.size()) {
if( p.lower_bound.size() ) {
uint64_t scope = convert_to_type<uint64_t>(p.lower_bound, "lower_bound scope");
lower = idx.lower_bound( boost::make_tuple(p.code, scope, p.table));
} else {
lower = idx.lower_bound(boost::make_tuple(p.code, 0, p.table));
std::get<1>(lower_bound_lookup_tuple) = scope;
}
if (p.upper_bound.size()) {
if( p.upper_bound.size() ) {
uint64_t scope = convert_to_type<uint64_t>(p.upper_bound, "upper_bound scope");
upper = idx.lower_bound( boost::make_tuple(p.code, scope, 0));
} else {
upper = idx.lower_bound(boost::make_tuple((uint64_t)p.code + 1, 0, 0));
std::get<1>(upper_bound_lookup_tuple) = scope;
}
auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time
unsigned int count = 0;
auto itr = lower;
read_only::get_table_by_scope_result result;
for (; itr != upper; ++itr) {
if (p.table && itr->table != p.table) {
if (fc::time_point::now() > end) {
break;
}
continue;
if( upper_bound_lookup_tuple < lower_bound_lookup_tuple )
return result;
auto walk_table_range = [&]( auto itr, auto end_itr ) {
auto cur_time = fc::time_point::now();
auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time
for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) {
if( p.table && itr->table != p.table ) continue;
result.rows.push_back( {itr->code, itr->scope, itr->table, itr->payer, itr->count} );
++count;
}
result.rows.push_back({itr->code, itr->scope, itr->table, itr->payer, itr->count});
if (++count == p.limit || fc::time_point::now() > end) {
++itr;
break;
if( itr != end_itr ) {
result.more = string(itr->scope);
}
};
auto lower = idx.lower_bound( lower_bound_lookup_tuple );
auto upper = idx.upper_bound( upper_bound_lookup_tuple );
if( p.reverse && *p.reverse ) {
walk_table_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) );
} else {
walk_table_range( lower, upper );
}
if (itr != upper) {
result.more = (string)itr->scope;
}
return result;
}
vector<asset> read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const {
const abi_def abi = eosio::chain_apis::get_abi( db, p.code );
auto table_type = get_table_type( abi, "accounts" );
(void)get_table_type( abi, "accounts" );
vector<asset> results;
walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){
......@@ -1237,7 +1278,7 @@ fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_p
fc::mutable_variant_object results;
const abi_def abi = eosio::chain_apis::get_abi( db, p.code );
auto table_type = get_table_type( abi, "stat" );
(void)get_table_type( abi, "stat" );
uint64_t scope = ( eosio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 );
......@@ -1585,17 +1626,12 @@ read_only::get_code_results read_only::get_code( const get_code_params& params )
EOS_ASSERT( params.code_as_wasm, unsupported_feature, "Returning WAST from get_code is no longer supported" );
if( accnt.code.size() ) {
if (params.code_as_wasm) {
result.wasm = string(accnt.code.begin(), accnt.code.end());
} else {
result.wast = wasm_to_wast( (const uint8_t*)accnt.code.data(), accnt.code.size(), true );
}
result.wasm = string(accnt.code.begin(), accnt.code.end());
result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() );
}
abi_def abi;
if( abi_serializer::to_abi(accnt.abi, abi) ) {
result.abi = std::move(abi);
}
......@@ -1693,7 +1729,7 @@ read_only::get_account_results read_only::get_account( const get_account_params&
auto core_symbol = extract_core_symbol();
if (params.expected_core_symbol.valid())
if (params.expected_core_symbol.valid())
core_symbol = *(params.expected_core_symbol);
const auto* t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( token_code, params.account_name, N(accounts) ));
......
......@@ -55,7 +55,7 @@ struct permission {
template<typename>
struct resolver_factory;
// see specialization for uint64_t in source file
// see specializations for uint64_t and double in source file
template<typename Type>
Type convert_to_type(const string& str, const string& desc) {
try {
......@@ -66,6 +66,9 @@ Type convert_to_type(const string& str, const string& desc) {
template<>
uint64_t convert_to_type(const string& str, const string& desc);
template<>
double convert_to_type(const string& str, const string& desc);
class read_only {
const controller& db;
const fc::microseconds abi_serializer_max_time;
......@@ -269,6 +272,8 @@ public:
string key_type; // type of key specified by index_position
string index_position; // 1 - primary (first), 2 - secondary index (in order defined by multi_index), 3 - third index, etc
string encode_type{"dec"}; //dec, hex , default=dec
optional<bool> reverse;
optional<bool> show_payer; // show RAM pyer
};
struct get_table_rows_result {
......@@ -284,6 +289,7 @@ public:
string lower_bound; // lower bound of scope, optional
string upper_bound; // upper bound of scope, optional
uint32_t limit = 10;
optional<bool> reverse;
};
struct get_table_by_scope_result_row {
name code;
......@@ -398,58 +404,78 @@ public:
const uint64_t table_with_index = get_table_index_name(p, primary);
const auto* t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(p.code, scope, p.table));
const auto* index_t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(p.code, scope, table_with_index));
if (t_id != nullptr && index_t_id != nullptr) {
const auto& secidx = d.get_index<IndexType, chain::by_secondary>();
decltype(index_t_id->id) low_tid(index_t_id->id._id);
decltype(index_t_id->id) next_tid(index_t_id->id._id + 1);
auto lower = secidx.lower_bound(boost::make_tuple(low_tid));
auto upper = secidx.lower_bound(boost::make_tuple(next_tid));
if( t_id != nullptr && index_t_id != nullptr ) {
using secondary_key_type = std::result_of_t<decltype(conv)(SecKeyType)>;
static_assert( std::is_same<typename IndexType::value_type::secondary_key_type, secondary_key_type>::value, "Return type of conv does not match type of secondary key for IndexType" );
if (p.lower_bound.size()) {
if (p.key_type == "name") {
const auto& secidx = d.get_index<IndexType, chain::by_secondary>();
auto lower_bound_lookup_tuple = std::make_tuple( index_t_id->id._id,
eosio::chain::secondary_key_traits<secondary_key_type>::true_lowest(),
std::numeric_limits<uint64_t>::lowest() );
auto upper_bound_lookup_tuple = std::make_tuple( index_t_id->id._id,
eosio::chain::secondary_key_traits<secondary_key_type>::true_highest(),
std::numeric_limits<uint64_t>::max() );
if( p.lower_bound.size() ) {
if( p.key_type == "name" ) {
name s(p.lower_bound);
SecKeyType lv = convert_to_type<SecKeyType>( s.to_string(), "lower_bound name" ); // avoids compiler error
lower = secidx.lower_bound( boost::make_tuple( low_tid, conv( lv )));
std::get<1>(lower_bound_lookup_tuple) = conv( lv );
} else {
SecKeyType lv = convert_to_type<SecKeyType>( p.lower_bound, "lower_bound" );
lower = secidx.lower_bound( boost::make_tuple( low_tid, conv( lv )));
std::get<1>(lower_bound_lookup_tuple) = conv( lv );
}
}
if (p.upper_bound.size()) {
if (p.key_type == "name") {
if( p.upper_bound.size() ) {
if( p.key_type == "name" ) {
name s(p.upper_bound);
SecKeyType uv = convert_to_type<SecKeyType>( s.to_string(), "upper_bound name" );
upper = secidx.lower_bound( boost::make_tuple( low_tid, conv( uv )));
std::get<1>(upper_bound_lookup_tuple) = conv( uv );
} else {
SecKeyType uv = convert_to_type<SecKeyType>( p.upper_bound, "upper_bound" );
upper = secidx.lower_bound( boost::make_tuple( low_tid, conv( uv )));
std::get<1>(upper_bound_lookup_tuple) = conv( uv );
}
}
vector<char> data;
auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time
unsigned int count = 0;
auto itr = lower;
for (; itr != upper; ++itr) {
const auto* itr2 = d.find<chain::key_value_object, chain::by_scope_primary>(boost::make_tuple(t_id->id, itr->primary_key));
if (itr2 == nullptr) continue;
copy_inline_row(*itr2, data);
if (p.json) {
result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) );
} else {
result.rows.emplace_back(fc::variant(data));
if( upper_bound_lookup_tuple < lower_bound_lookup_tuple )
return result;
auto walk_table_row_range = [&]( auto itr, auto end_itr ) {
auto cur_time = fc::time_point::now();
auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time
vector<char> data;
for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) {
const auto* itr2 = d.find<chain::key_value_object, chain::by_scope_primary>( boost::make_tuple(t_id->id, itr->primary_key) );
if( itr2 == nullptr ) continue;
copy_inline_row(*itr2, data);
fc::variant data_var;
if( p.json ) {
data_var = abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors );
} else {
data_var = fc::variant( data );
}
if( p.show_payer && *p.show_payer ) {
result.rows.emplace_back( fc::mutable_variant_object("data", std::move(data_var))("payer", itr->payer) );
} else {
result.rows.emplace_back( std::move(data_var) );
}
++count;
}
if (++count == p.limit || fc::time_point::now() > end) {
break;
if( itr != end_itr ) {
result.more = true;
}
}
if (itr != upper) {
result.more = true;
};
auto lower = secidx.lower_bound( lower_bound_lookup_tuple );
auto upper = secidx.upper_bound( upper_bound_lookup_tuple );
if( p.reverse && *p.reverse ) {
walk_table_row_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) );
} else {
walk_table_row_range( lower, upper );
}
}
return result;
......@@ -465,53 +491,65 @@ public:
abi_serializer abis;
abis.set_abi(abi, abi_serializer_max_time);
const auto* t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(p.code, scope, p.table));
if (t_id != nullptr) {
if( t_id != nullptr ) {
const auto& idx = d.get_index<IndexType, chain::by_scope_primary>();
decltype(t_id->id) next_tid(t_id->id._id + 1);
auto lower = idx.lower_bound(boost::make_tuple(t_id->id));
auto upper = idx.lower_bound(boost::make_tuple(next_tid));
auto lower_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits<uint64_t>::lowest() );
auto upper_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits<uint64_t>::max() );
if (p.lower_bound.size()) {
if (p.key_type == "name") {
if( p.lower_bound.size() ) {
if( p.key_type == "name" ) {
name s(p.lower_bound);
lower = idx.lower_bound( boost::make_tuple( t_id->id, s.value ));
std::get<1>(lower_bound_lookup_tuple) = s.value;
} else {
auto lv = convert_to_type<typename IndexType::value_type::key_type>( p.lower_bound, "lower_bound" );
lower = idx.lower_bound( boost::make_tuple( t_id->id, lv ));
std::get<1>(lower_bound_lookup_tuple) = lv;
}
}
if (p.upper_bound.size()) {
if (p.key_type == "name") {
if( p.upper_bound.size() ) {
if( p.key_type == "name" ) {
name s(p.upper_bound);
upper = idx.lower_bound( boost::make_tuple( t_id->id, s.value ));
std::get<1>(upper_bound_lookup_tuple) = s.value;
} else {
auto uv = convert_to_type<typename IndexType::value_type::key_type>( p.upper_bound, "upper_bound" );
upper = idx.lower_bound( boost::make_tuple( t_id->id, uv ));
std::get<1>(upper_bound_lookup_tuple) = uv;
}
}
vector<char> data;
auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time
unsigned int count = 0;
auto itr = lower;
for (; itr != upper; ++itr) {
copy_inline_row(*itr, data);
if (p.json) {
result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) );
} else {
result.rows.emplace_back(fc::variant(data));
if( upper_bound_lookup_tuple < lower_bound_lookup_tuple )
return result;
auto walk_table_row_range = [&]( auto itr, auto end_itr ) {
auto cur_time = fc::time_point::now();
auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time
vector<char> data;
for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++count, ++itr, cur_time = fc::time_point::now() ) {
copy_inline_row(*itr, data);
fc::variant data_var;
if( p.json ) {
data_var = abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors );
} else {
data_var = fc::variant( data );
}
if( p.show_payer && *p.show_payer ) {
result.rows.emplace_back( fc::mutable_variant_object("data", std::move(data_var))("payer", itr->payer) );
} else {
result.rows.emplace_back( std::move(data_var) );
}
}
if (++count == p.limit || fc::time_point::now() > end) {
++itr;
break;
if( itr != end_itr ) {
result.more = true;
}
}
if (itr != upper) {
result.more = true;
};
auto lower = idx.lower_bound( lower_bound_lookup_tuple );
auto upper = idx.upper_bound( upper_bound_lookup_tuple );
if( p.reverse && *p.reverse ) {
walk_table_row_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) );
} else {
walk_table_row_range( lower, upper );
}
}
return result;
......@@ -622,7 +660,7 @@ public:
void plugin_shutdown();
chain_apis::read_only get_read_only_api() const { return chain_apis::read_only(chain(), get_abi_serializer_max_time()); }
chain_apis::read_write get_read_write_api();
chain_apis::read_write get_read_write_api() { return chain_apis::read_write(chain(), get_abi_serializer_max_time()); }
void accept_block( const chain::signed_block_ptr& block );
void accept_transaction(const chain::packed_transaction& trx, chain::plugin_interface::next_function<chain::transaction_trace_ptr> next);
......@@ -672,10 +710,10 @@ FC_REFLECT(eosio::chain_apis::read_only::get_block_header_state_params, (block_n
FC_REFLECT( eosio::chain_apis::read_write::push_transaction_results, (transaction_id)(processed) )
FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit)(key_type)(index_position)(encode_type) )
FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit)(key_type)(index_position)(encode_type)(reverse)(show_payer) )
FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_result, (rows)(more) );
FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_params, (code)(table)(lower_bound)(upper_bound)(limit) )
FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_params, (code)(table)(lower_bound)(upper_bound)(limit)(reverse) )
FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_result_row, (code)(scope)(table)(payer)(count));
FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_result, (rows)(more) );
......
......@@ -4,7 +4,6 @@
*/
#include <eosio/faucet_testnet_plugin/faucet_testnet_plugin.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio/utilities/key_conversion.hpp>
#include <fc/variant.hpp>
#include <fc/io/json.hpp>
......
......@@ -11,7 +11,6 @@
#include <eosio/chain/block.hpp>
#include <eosio/chain/plugin_interface.hpp>
#include <eosio/producer_plugin/producer_plugin.hpp>
#include <eosio/utilities/key_conversion.hpp>
#include <eosio/chain/contract_types.hpp>
#include <fc/network/message_buffer.hpp>
......@@ -1514,9 +1513,10 @@ namespace eosio {
req.req_blocks.mode = catch_up;
for (auto cc : my_impl->connections) {
if (cc->fork_head == id ||
cc->fork_head_num > num)
cc->fork_head_num > num) {
req.req_blocks.mode = none;
break;
break;
}
}
if( req.req_blocks.mode == catch_up ) {
c->fork_head = id;
......@@ -2379,7 +2379,7 @@ namespace eosio {
request_message req;
bool send_req = false;
if (msg.known_trx.mode != none) {
fc_dlog(logger,"this is a ${m} notice with ${n} blocks", ("m",modes_str(msg.known_trx.mode))("n",msg.known_trx.pending));
fc_dlog(logger,"this is a ${m} notice with ${n} transactions", ("m",modes_str(msg.known_trx.mode))("n",msg.known_trx.pending));
}
switch (msg.known_trx.mode) {
case none:
......@@ -2413,9 +2413,6 @@ namespace eosio {
}
switch (msg.known_blocks.mode) {
case none : {
if (msg.known_trx.mode != normal) {
return;
}
break;
}
case last_irr_catch_up:
......
......@@ -5,6 +5,6 @@ add_library( producer_plugin
${HEADERS}
)
target_link_libraries( producer_plugin chain_plugin http_client_plugin appbase eosio_chain eos_utilities )
target_link_libraries( producer_plugin chain_plugin http_client_plugin appbase eosio_chain )
target_include_directories( producer_plugin
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" )
......@@ -285,18 +285,22 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
};
void on_incoming_block(const signed_block_ptr& block) {
fc_dlog(_log, "received incoming block ${id}", ("id", block->id()));
auto id = block->id();
EOS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds(7)), block_from_the_future, "received a block from the future, ignoring it" );
fc_dlog(_log, "received incoming block ${id}", ("id", id));
EOS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds( 7 )), block_from_the_future,
"received a block from the future, ignoring it: ${id}", ("id", id) );
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
/* de-dupe here... no point in aborting block if we already know the block */
auto id = block->id();
auto existing = chain.fetch_block_by_id( id );
if( existing ) { return; }
// start processing of block
auto bsf = chain.create_block_state_future( block );
// abort the pending block
chain.abort_block();
......@@ -308,7 +312,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
// push the new block
bool except = false;
try {
chain.push_block(block);
chain.push_block( bsf );
} catch ( const guard_exception& e ) {
app().get_plugin<chain_plugin>().handle_guard_exception(e);
return;
......
BasedOnStyle: LLVM
IndentWidth: 3
ColumnLimit: 120
PointerAlignment: Left
AlwaysBreakTemplateDeclarations: true
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
BreakConstructorInitializers: BeforeComma
file(GLOB HEADERS "include/eosio/state_history_plugin/*.hpp")
add_library( state_history_plugin
state_history_plugin.cpp
state_history_plugin_abi.cpp
${HEADERS} )
target_link_libraries( state_history_plugin chain_plugin eosio_chain appbase )
target_include_directories( state_history_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <boost/filesystem.hpp>
#include <fstream>
#include <stdint.h>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/types.hpp>
#include <fc/log/logger.hpp>
namespace eosio {
/*
* *.log:
* +---------+----------------+-----------+------------------+-----+---------+----------------+
* | Entry i | Pos of Entry i | Entry i+1 | Pos of Entry i+1 | ... | Entry z | Pos of Entry z |
* +---------+----------------+-----------+------------------+-----+---------+----------------+
*
* *.index:
* +-----------+-------------+-----+-----------+
* | Summary i | Summary i+1 | ... | Summary z |
* +-----------+-------------+-----+-----------+
*
* each entry:
* uint32_t block_num
* block_id_type block_id
* uint64_t size of payload
* uint8_t version
* payload
*
* each summary:
* uint64_t position of entry in *.log
*
* state payload:
* uint32_t size of deltas
* char[] deltas
*/
// todo: look into switching this to serialization instead of memcpy
// todo: consider reworking versioning
// todo: consider dropping block_num since it's included in block_id
// todo: currently only checks version on the first record. Need in recover_blocks
struct state_history_log_header {
uint32_t block_num = 0;
chain::block_id_type block_id;
uint64_t payload_size = 0;
uint8_t version = 0;
};
struct state_history_summary {
uint64_t pos = 0;
};
class state_history_log {
private:
const char* const name = "";
std::string log_filename;
std::string index_filename;
std::fstream log;
std::fstream index;
uint32_t _begin_block = 0;
uint32_t _end_block = 0;
chain::block_id_type last_block_id;
public:
state_history_log(const char* const name, std::string log_filename, std::string index_filename)
: name(name)
, log_filename(std::move(log_filename))
, index_filename(std::move(index_filename)) {
open_log();
open_index();
}
uint32_t begin_block() const { return _begin_block; }
uint32_t end_block() const { return _end_block; }
template <typename F>
void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) {
EOS_ASSERT(_begin_block == _end_block || header.block_num <= _end_block, chain::plugin_exception,
"missed a block in ${name}.log", ("name", name));
if (_begin_block != _end_block && header.block_num > _begin_block) {
if (header.block_num == _end_block) {
EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log",
("name", name));
} else {
state_history_log_header prev;
get_entry(header.block_num - 1, prev);
EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log",
("name", name));
}
}
if (header.block_num < _end_block)
truncate(header.block_num);
log.seekg(0, std::ios_base::end);
uint64_t pos = log.tellg();
log.write((char*)&header, sizeof(header));
write_payload(log);
uint64_t end = log.tellg();
EOS_ASSERT(end == pos + sizeof(header) + header.payload_size, chain::plugin_exception,
"wrote payload with incorrect size to ${name}.log", ("name", name));
log.write((char*)&pos, sizeof(pos));
index.seekg(0, std::ios_base::end);
state_history_summary summary{.pos = pos};
index.write((char*)&summary, sizeof(summary));
if (_begin_block == _end_block)
_begin_block = header.block_num;
_end_block = header.block_num + 1;
last_block_id = header.block_id;
}
// returns stream positioned at payload
std::fstream& get_entry(uint32_t block_num, state_history_log_header& header) {
EOS_ASSERT(block_num >= _begin_block && block_num < _end_block, chain::plugin_exception,
"read non-existing block in ${name}.log", ("name", name));
log.seekg(get_pos(block_num));
log.read((char*)&header, sizeof(header));
return log;
}
chain::block_id_type get_block_id(uint32_t block_num) {
state_history_log_header header;
get_entry(block_num, header);
return header.block_id;
}
private:
bool get_last_block(uint64_t size) {
state_history_log_header header;
uint64_t suffix;
log.seekg(size - sizeof(suffix));
log.read((char*)&suffix, sizeof(suffix));
if (suffix > size || suffix + sizeof(header) > size) {
elog("corrupt ${name}.log (2)", ("name", name));
return false;
}
log.seekg(suffix);
log.read((char*)&header, sizeof(header));
if (suffix + sizeof(header) + header.payload_size + sizeof(suffix) != size) {
elog("corrupt ${name}.log (3)", ("name", name));
return false;
}
_end_block = header.block_num + 1;
last_block_id = header.block_id;
if (_begin_block >= _end_block) {
elog("corrupt ${name}.log (4)", ("name", name));
return false;
}
return true;
}
void recover_blocks(uint64_t size) {
ilog("recover ${name}.log", ("name", name));
uint64_t pos = 0;
uint32_t num_found = 0;
while (true) {
state_history_log_header header;
if (pos + sizeof(header) > size)
break;
log.seekg(pos);
log.read((char*)&header, sizeof(header));
uint64_t suffix;
if (header.payload_size > size || pos + sizeof(header) + header.payload_size + sizeof(suffix) > size)
break;
log.seekg(pos + sizeof(header) + header.payload_size);
log.read((char*)&suffix, sizeof(suffix));
if (suffix != pos)
break;
pos = pos + sizeof(header) + header.payload_size + sizeof(suffix);
if (!(++num_found % 10000)) {
printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos);
fflush(stdout);
}
}
log.flush();
boost::filesystem::resize_file(log_filename, pos);
log.sync();
EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name));
}
void open_log() {
log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app);
log.seekg(0, std::ios_base::end);
uint64_t size = log.tellg();
if (size >= sizeof(state_history_log_header)) {
state_history_log_header header;
log.seekg(0);
log.read((char*)&header, sizeof(header));
EOS_ASSERT(header.version == 0 && sizeof(header) + header.payload_size + sizeof(uint64_t) <= size,
chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name));
_begin_block = header.block_num;
last_block_id = header.block_id;
if (!get_last_block(size))
recover_blocks(size);
ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1));
} else {
EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name));
ilog("${name}.log is empty", ("name", name));
}
}
void open_index() {
index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app);
index.seekg(0, std::ios_base::end);
if (index.tellg() == (_end_block - _begin_block) * sizeof(state_history_summary))
return;
ilog("Regenerate ${name}.index", ("name", name));
index.close();
index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc);
log.seekg(0, std::ios_base::end);
uint64_t size = log.tellg();
uint64_t pos = 0;
uint32_t num_found = 0;
while (pos < size) {
state_history_log_header header;
EOS_ASSERT(pos + sizeof(header) <= size, chain::plugin_exception, "corrupt ${name}.log (6)", ("name", name));
log.seekg(pos);
log.read((char*)&header, sizeof(header));
uint64_t suffix_pos = pos + sizeof(header) + header.payload_size;
uint64_t suffix;
EOS_ASSERT(suffix_pos + sizeof(suffix) <= size, chain::plugin_exception, "corrupt ${name}.log (7)",
("name", name));
log.seekg(suffix_pos);
log.read((char*)&suffix, sizeof(suffix));
// ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}",
// ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size));
EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name));
state_history_summary summary{.pos = pos};
index.write((char*)&summary, sizeof(summary));
pos = suffix_pos + sizeof(suffix);
if (!(++num_found % 10000)) {
printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos);
fflush(stdout);
}
}
}
uint64_t get_pos(uint32_t block_num) {
state_history_summary summary;
index.seekg((block_num - _begin_block) * sizeof(summary));
index.read((char*)&summary, sizeof(summary));
return summary.pos;
}
void truncate(uint32_t block_num) {
log.flush();
index.flush();
uint64_t num_removed = 0;
if (block_num <= _begin_block) {
num_removed = _end_block - _begin_block;
log.seekg(0);
index.seekg(0);
boost::filesystem::resize_file(log_filename, 0);
boost::filesystem::resize_file(index_filename, 0);
_begin_block = _end_block = 0;
} else {
num_removed = _end_block - block_num;
uint64_t pos = get_pos(block_num);
log.seekg(0);
index.seekg(0);
boost::filesystem::resize_file(log_filename, pos);
boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(state_history_summary));
_end_block = block_num;
}
log.sync();
index.sync();
ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name));
}
}; // state_history_log
} // namespace eosio
此差异已折叠。
......@@ -4,6 +4,6 @@ add_library( test_control_plugin
test_control_plugin.cpp
${HEADERS} )
target_link_libraries( test_control_plugin producer_plugin chain_plugin http_client_plugin appbase eosio_chain eos_utilities )
target_link_libraries( test_control_plugin producer_plugin chain_plugin http_client_plugin appbase eosio_chain )
target_include_directories( test_control_plugin
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
......@@ -5,7 +5,6 @@
#include <eosio/txn_test_gen_plugin/txn_test_gen_plugin.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio/utilities/key_conversion.hpp>
#include <fc/variant.hpp>
#include <fc/io/json.hpp>
......
......@@ -305,6 +305,14 @@ se_wallet::se_wallet() : my(new detail::se_wallet_impl()) {
return;
}
}
if(sscanf(model, "Macmini%u", &major) == 1 && major >= 8) {
my->populate_existing_keys();
return;
}
if(sscanf(model, "MacBookAir%u", &major) == 1 && major >= 8) {
my->populate_existing_keys();
return;
}
}
EOS_THROW(secure_enclave_exception, "Secure Enclave not supported on this hardware");
......
......@@ -2,5 +2,4 @@ add_subdirectory( nodeos )
add_subdirectory( cleos )
add_subdirectory( keosd )
add_subdirectory( eosio-launcher )
add_subdirectory( eosio-abigen )
add_subdirectory( eosio-blocklog )
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册