未验证 提交 0213826c 编写于 作者: Z zorba80 提交者: GitHub

Merge branch 'master' into master-bta-1307

......@@ -8,6 +8,8 @@
*.wasm
*.s
*.dot
*.abi.hpp
*.cmake
\#*
\.#*
CMakeCache.txt
......
......@@ -20,6 +20,7 @@ matrix:
- libgmp-dev
- libclang-4.0-dev
- python3
- sharutils
- os: osx
osx_image: xcode9.1
before_install:
......@@ -49,7 +50,7 @@ before_install:
cd boost_1_64_0
./bootstrap.sh --prefix=$TRAVIS_BUILD_DIR/ext
echo 'using clang : 4.0 : clang++-4.0 ;' >> project-config.jam
./b2 -d0 -j4 --with-thread --with-date_time --with-system --with-filesystem --with-program_options --with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine toolset=clang link=static install
./b2 -d0 -j4 --with-iostreams --with-thread --with-date_time --with-system --with-filesystem --with-program_options --with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine toolset=clang link=static install
cd $TRAVIS_BUILD_DIR/ext
wget https://cmake.org/files/v3.9/cmake-3.9.0-Linux-x86_64.tar.gz
tar xzf cmake-3.9.0-Linux-x86_64.tar.gz
......@@ -79,3 +80,15 @@ script:
- ninja -j4
- '[ "$TRAVIS_OS_NAME" == "osx" ] || ctest --output-on-failure'
- cpack
deploy:
provider: releases
api_key:
secure: "PvCGYnK5Wq0MdB141TSuS7tljYRs7BAlk4tUzvYcHV/8s+cocKGA6DBzeXAVIAahc6r0ccKxMSZV98J6FBa3cdHLvay0qnihXsg8YR2gk3O2Ei8v38WO+BmRJ94W79vvRkmd7bbIDylhyWnTjWXt0eNWbeuZxPrIkEFTDu9hxsvcTX+WzamRRtPaqUhddO7VMsV+KKYsegzSKd9OiMk4+1dieNfkp0P6gWBoPw/9t5NIj4tFDpDmvUcWXy4y2ENQY9YULuFaRd+SjvfciAMznqf3wOAxXBa5NXCfUPHPEt+cC5rvOrvI3CTduJL2sFY5628Z3iGEoc9pSe/GJiygcl6CQkH9BkDMH8TpID6kPhfXqg1ObKe5AwNcNX009PdTGl0pdljrVETHOtMk8tPLyg9BoMBU6i+rePHxIlrBRj1VYX4qoidPTA0EcauFj3t4c5cOtamgovIt+U3HSI3+UhCl7+yF6YFKi0y8NAFNDYp3EdeCdvOzBLvoScBUGoWdDEm99HZTqdfd/OJlHqWJHR8DE+PW64OaDjs+2q0Sn3n5+huy9zvimMUl0XfsErthSLhGTAIn0Ipl1UBmZgZa4Rbrc0DpWv6rDZBCEu3JPFJS/x5gMT2DuQg/JUO5f5WJjIAUWI4hD/z80pzheky07hEBTKbAQqGwE1GKwFNfkLw="
file: "$TRAVIS_BUILD_DIR/build/packages/EOS.IO-*"
skip_cleanup: true
file_glob: true
on:
tags: true
repo: EOSIO/eos
branch: master
......@@ -77,7 +77,8 @@ FIND_PACKAGE(Boost 1.64 REQUIRED COMPONENTS
chrono
unit_test_framework
context
locale)
locale
iostreams)
if( WIN32 )
......@@ -159,7 +160,9 @@ endif( WIN32 )
set(ENABLE_COVERAGE_TESTING FALSE CACHE BOOL "Build Eos for code coverage analysis")
if(ENABLE_COVERAGE_TESTING)
SET(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}")
SET(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}")
find_program( LCOV_PATH lcov )
find_program( GENHTML_PATH NAMES genhtml)
endif()
include(wasm)
......@@ -169,9 +172,7 @@ if(WASM_TOOLCHAIN)
message(STATUS "Using WASM llvm-link => " ${WASM_LLVM_LINK})
add_subdirectory(contracts)
else()
message(STATUS "--------------------------------------------------------------------")
message(STATUS "No WASM compiler could be found ... (skipping building of contracts)")
message(STATUS "--------------------------------------------------------------------")
message( FATAL_ERROR "No WASM compiler cound be found" )
endif()
include(installer)
......
......@@ -63,6 +63,7 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER)
# NOTE: Setting SOURCE_FILE and looping over it to avoid cmake issue with compilation ${target}.bc's rule colliding with
# linking ${target}.bc's rule
set(SOURCE_FILE ${target}.cpp)
set(outfiles "")
foreach(srcfile ${SOURCE_FILE})
get_filename_component(outfile ${srcfile} NAME)
......@@ -137,10 +138,11 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER)
VERBATIM
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wast)
STRING (REPLACE "." "_" TARGET_VARIABLE "${target}")
add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast.hpp
DEPENDS ${DESTINATION_FOLDER}/${target}.wast
COMMAND echo "const char* ${target}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMAND echo "const char* const ${TARGET_VARIABLE}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMAND cat ${DESTINATION_FOLDER}/${target}.wast >> ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMENT "Generating ${target}.wast.hpp"
......@@ -150,7 +152,7 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER)
if (EXISTS ${DESTINATION_FOLDER}/${target}.abi )
add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.abi.hpp
DEPENDS ${DESTINATION_FOLDER}/${target}.abi
COMMAND echo "const char* ${target}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMAND echo "const char* const ${TARGET_VARIABLE}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMAND cat ${DESTINATION_FOLDER}/${target}.abi >> ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMENT "Generating ${target}.abi.hpp"
......
......@@ -31,7 +31,7 @@ RUN wget https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.
&& ./bootstrap.sh --prefix=/usr/local \
&& echo 'using clang : 4.0 : clang++-4.0 ;' >> project-config.jam \
&& ./b2 -d0 -j4 --with-thread --with-date_time --with-system --with-filesystem --with-program_options \
--with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine toolset=clang link=static install \
--with-signals --with-serialization --with-chrono --with-test --with-context --with-locale --with-coroutine --with-iostreams toolset=clang link=static install \
&& cd .. && rm -rf boost_1_64_0
RUN wget https://github.com/mongodb/mongo-c-driver/releases/download/1.8.0/mongo-c-driver-1.8.0.tar.gz -O - | tar -xz \
......
......@@ -27,7 +27,7 @@ The public testnet described in the [wiki](https://github.com/EOSIO/eos/wiki/Tes
2. [Setting up a build/development environment](#setup)
1. [Automated build script](#autobuild)
1. [Clean install Ubuntu 16.10 for a local testnet](#autoubuntulocal)
2. [Clean install Ubuntu 16.10 for the public testnet](#autobuntupublic)
2. [Clean install Ubuntu 16.10 for the public testnet](#autoubuntupublic)
3. [MacOS Sierra 10.12.6 for a local testnet](#automaclocal)
4. [MacOS Sierra 10.12.6 for the public testnet](#automacpublic)
3. [Building EOS and running a node](#runanode)
......@@ -61,25 +61,29 @@ The following instructions detail the process of getting the software, building
For Ubuntu 16.10 and MacOS Sierra, there is an automated build script that can install all dependencies and builds EOS.
It is called build.sh with the following inputs.
It is called eosio-build.sh with the following inputs.
- architecture [ubuntu|darwin]
- optional mode [full|build]
The second optional input can be `full` or `build` where `full` implies that it installs dependencies and builds eos. If you omit this input then the build script installs dependencies and then builds eos.
```bash
./build.sh <architecture> <optional mode>
./eosio-build.sh <architecture> <optional mode>
```
Choose whether you will be building for a local testnet or for the public testnet and jump to the appropriate section below. Clone the EOS repository recursively as described and run build.sh located in the root `eos` folder.
Choose whether you will be building for a local testnet or for the public testnet and jump to the appropriate section below. Clone the EOS repository recursively as described and run eosio-build.sh located in the root `eos` folder.
:warning: **As of February 2018, `master` is under heavy development and is not suitable for experimentation.** :warning:
We strongly recommend following the instructions for building the public testnet version for [Ubuntu](#autoubuntupublic) or [Mac OS X](#automacpublic). `master` is in pieces on the garage floor while we rebuild this hotrod. This notice will be removed when `master` is usable again. Your patience is appreciated.
<a name="autoubuntulocal"></a>
#### Clean install Ubuntu 16.10 for a local testnet
#### :no_entry: Clean install Ubuntu 16.10 for a local testnet :no_entry:
```bash
git clone https://github.com/eosio/eos --recursive
cd eos
./build.sh ubuntu
./eosio-build.sh ubuntu
```
Now you can proceed to the next step - [Creating and launching a single-node testnet](#singlenode)
......@@ -92,13 +96,13 @@ git clone https://github.com/eosio/eos --recursive
cd eos
git checkout dawn-2.x
./build.sh ubuntu
./eosio-build.sh ubuntu
```
Now you can proceed to the next step - [Running a node on the public testnet](#publictestnet)
<a name="automaclocal"></a>
#### MacOS Sierra for a local testnet
#### :no_entry: MacOS Sierra for a local testnet :no_entry:
Before running the script make sure you have updated XCode and brew:
......@@ -107,13 +111,13 @@ xcode-select --install
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
Then clone the EOS repository recursively and run build.sh in the root `eos` folder.
Then clone the EOS repository recursively and run eosio-build.sh in the root `eos` folder.
```bash
git clone https://github.com/eosio/eos --recursive
cd eos
./build.sh darwin
./eosio-build.sh darwin
```
Now you can proceed to the next step - [Creating and launching a single-node testnet](#singlenode)
......@@ -128,14 +132,14 @@ xcode-select --install
ruby -e "$(curl -fsSl https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
Then clone the EOS repository recursively, checkout the branch that is compatible with the public testnet, and run build.sh in the root `eos` folder.
Then clone the EOS repository recursively, checkout the branch that is compatible with the public testnet, and run eosio-build.sh in the root `eos` folder.
```bash
git clone https://github.com/eosio/eos --recursive
cd eos
git checkout dawn-2.x
./build.sh darwin
./eosio-build.sh darwin
```
Now you can proceed to the next step - [Running a node on the public testnet](#publictestnet)
......@@ -184,8 +188,8 @@ EOS comes with a number of programs you can find in `~/eos/build/programs`. They
* eosiod - server-side blockchain node component
* eosioc - command line interface to interact with the blockchain
* eosio-walletd - EOS wallet
* launcher - application for nodes network composing and deployment; [more on launcher](https://github.com/EOSIO/eos/blob/master/testnet.md)
* eosiowd - EOS wallet
* eosio-launcher - application for nodes network composing and deployment; [more on eosio-launcher](https://github.com/EOSIO/eos/blob/master/testnet.md)
<a name="singlenode"></a>
### Creating and launching a single-node testnet
......@@ -425,14 +429,14 @@ As expected, the receiving account **inita** now has a balance of **20** tokens,
<a name="localtestnet"></a>
## Running multi-node local testnet
To run a local testnet you can use a `launcher` application provided in the `~/eos/build/programs/launcher` folder.
To run a local testnet you can use the `eosio-launcher` application provided in the `~/eos/build/programs/eosio-launcher` folder.
For testing purposes you will run two local production nodes talking to each other.
```bash
cd ~/eos/build
cp ../genesis.json ./
./programs/launcher/launcher -p2 --skip-signature
./programs/eosio-launcher/eosio-launcher -p2 --skip-signature
```
This command will generate two data folders for each instance of the node: `tn_data_00` and `tn_data_01`.
......@@ -453,7 +457,7 @@ To confirm the nodes are running, run the following `eosioc` commands:
For each command, you should get a JSON response with blockchain information.
You can read more on launcher and its settings [here](https://github.com/EOSIO/eos/blob/master/testnet.md)
You can read more on eosio-launcher and its settings [here](https://github.com/EOSIO/eos/blob/master/testnet.md)
<a name="publictestnet"></a>
## Running a local node connected to the public testnet
......
add_subdirectory(eosio.system)
add_subdirectory(identity)
add_subdirectory(currency)
#add_subdirectory(bancor)
#add_subdirectory(eosio.system)
......@@ -10,6 +11,7 @@ add_subdirectory(test_api)
#add_subdirectory(simpledb)
#add_subdirectory(storage)
#add_subdirectory(social)
add_subdirectory(noop)
install( DIRECTORY eosiolib DESTINATION include/ )
install( DIRECTORY skeleton DESTINATION share/ )
......@@ -3,7 +3,7 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
namespace asserter {
struct PACKED(assertdef) {
......@@ -11,4 +11,4 @@ namespace asserter {
int8_t message_length;
char message[];
};
}
\ No newline at end of file
}
......@@ -3,7 +3,7 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/generic_currency.hpp>
......
......@@ -10,8 +10,16 @@
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"uint64"}
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
]
},{
"name": "issue",
"base": "",
"fields": [
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"}
]
},{
"name": "account",
"base": "",
......@@ -19,11 +27,23 @@
{"name":"key", "type":"name"},
{"name":"balance", "type":"uint64"}
]
},{
"name": "nonce",
"base": "",
"fields": [
{"name":"value", "type":"string"}
]
}
],
"actions": [{
"name": "transfer",
"type": "transfer"
},{
"name": "issue",
"type": "issue"
},{
"name": "nonce",
"type": "nonce"
}
],
"tables": [{
......
......@@ -2,10 +2,11 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/reflect.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/generic_currency.hpp>
#include <eosiolib/datastream.hpp>
......@@ -19,6 +20,34 @@ namespace eosiosystem {
static const account_name system_account = N(eosio.system);
typedef eosio::generic_currency< eosio::token<system_account,S(4,EOS)> > currency;
struct total_bandwidth {
account_name owner;
typename currency::token_type total_net_weight;
typename currency::token_type total_cpu_weight;
};
typedef eosio::table64<SystemAccount, N(totalband), total_bandwidth> total_bandwidth;
struct delegated_bandwidth {
account_name from;
account_name to;
typename currency::token_type net_weight;
typename currency::token_type cpu_weight;
uint32_t start_pending_net_withdraw = 0;
typename currency::token_type pending_net_withdraw;
uint64_t deferred_net_withdraw_handler = 0;
uint32_t start_pending_cpu_withdraw = 0;
typename currency::token_type pending_cpu_withdraw;
uint64_t deferred_cpu_withdraw_handler = 0;
};
ACTION( SystemAccount, finshundel ) {
account_name from;
account_name to;
};
ACTION( SystemAccount, regproducer ) {
account_name producer_to_register;
......@@ -31,6 +60,35 @@ namespace eosiosystem {
EOSLIB_SERIALIZE( regproxy, (proxy_to_register) );
};
ACTION( SystemAccount, delnetbw ) {
account_name from;
account_name receiver;
typename currency::token_type stake_quantity;
EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) )
};
ACTION( SystemAccount, undelnetbw ) {
account_name from;
account_name receiver;
typename currency::token_type stake_quantity;
EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) )
};
ACTION( SystemAccount, nonce ) {
eosio::string value;
EOSLIB_SERIALIZE( nonce, (value) );
};
static void on( const delnetbw& del ) {
require_auth( del.from );
// require_account( receiver );
currency::inline_transfer( del.from, SystemAccount, del.stake_quantity, "stake bandwidth" );
}
static void on( const regproducer& reg ) {
require_auth( reg.producer_to_register );
}
......@@ -39,16 +97,15 @@ namespace eosiosystem {
require_auth( reg.proxy_to_register );
}
static void on( const nonce& ) {
}
static void apply( account_name code, action_name act ) {
if( !eosio::dispatch<contract,
// typename currency::transfer_memo,
// typename currency::issue,
regproducer,
regproxy
>( code, act) )
{
assert( false, "received unexpected action" );
if( !eosio::dispatch<contract, regproducer, regproxy, nonce>( code, act) ) {
if ( !eosio::dispatch<currency, typename currency::transfer_memo, typename currency::issue>( code, act ) ) {
eosio::print("Unexpected action: ", act, "\n");
assert( false, "received unexpected action");
}
}
} /// apply
};
......
#pragma once
#include <eosiolib/print.hpp>
#include <eosiolib/action.hpp>
namespace eosio {
template<typename Contract, typename FirstAction>
......
......@@ -104,7 +104,7 @@ Get information related to an account.
@subsubsection examplegetaccount Example get_account Usage
```
$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"name":"inita"}'
$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"account_name":"inita"}'
```
@subsubsection examplegetaccountresult Example get_account Result
......
#pragma once
#include <eosiolib/db.hpp>
#include <eosiolib/raw.hpp>
#include <eosiolib/datastream.hpp>
namespace eosio {
......@@ -31,7 +31,7 @@ namespace eosio {
datastream<const char*> ds(temp + sizeof(SingletonName), read);
T result;
raw::unpack( ds, result );
unpack( ds, result );
return result;
}
......@@ -53,7 +53,7 @@ namespace eosio {
}
static void set( const T& value = T(), scope_name scope = Code ) {
auto size = raw::pack_size( value );
auto size = pack_size( value );
char buf[size+ sizeof(SingletonName)];
assert( sizeof(buf) <= 1024 + 8, "singleton too big to store" );
......
#pragma once
#include <eosiolib/db.h>
namespace eosio {
......@@ -44,6 +45,21 @@ namespace eosio {
return result;
}
static T get_or_default( uint64_t key, scope_name scope = DefaultScope, const T& def = T() ) {
char temp[1024];
*reinterpret_cast<uint64_t *>(temp) = key;
auto read = load_i64( scope, DefaultScope, TableName, temp, sizeof(temp) );
if( read < 0 ) {
return def;
}
datastream<const char*> ds(temp, read);
T result;
ds >> result;
return result;
}
static void set( const T& value = T(), scope_name scope = DefaultScope, uint64_t bta = BillToAccount ) {
auto size = pack_size( value );
char buf[size];
......@@ -52,8 +68,72 @@ namespace eosio {
datastream<char*> ds( buf, size );
ds << value;
store_i64( scope, TableName, bta, buf, sizeof(buf) );
store_i64( scope, TableName, bta, buf, ds.tellp() );
}
static void remove( uint64_t key, scope_name scope = DefaultScope ) {
remove_i64(scope, TableName, &key);
}
};
template<uint64_t Code, uint64_t TableName, typename T>
class table_i64i64i64 {
public:
table_i64i64i64( uint64_t scope = Code )
:_scope(scope){}
bool primary_lower_bound( T& result,
uint64_t primary = 0,
uint64_t secondary = 0,
uint64_t tertiary = 0 ) {
uint64_t temp[1024/8];
temp[0] = primary;
temp[1] = secondary;
temp[2] = tertiary;
auto read = lower_bound_primary_i64i64i64( Code, _scope, TableName,
(char*)temp, sizeof(temp) );
if( read <= 0 ) {
return false;
}
datastream<const char*> ds( (char*)temp, sizeof(temp) );
ds >> result;
return true;
}
bool next_primary( T& result, const T& current ) {
uint64_t temp[1024/8];
memcpy( temp, (const char*)&current, 3*sizeof(uint64_t) );
auto read = next_primary_i64i64i64( Code, _scope, TableName,
(char*)temp, sizeof(temp) );
if( read <= 0 ) {
return false;
}
datastream<const char*> ds( (char*)temp, sizeof(temp) );
ds >> result;
return true;
}
void store( const T& value, account_name bill_to ) {
char temp[1024];
datastream<char*> ds(temp, sizeof(temp) );
ds << value;
store_i64i64i64( _scope, TableName, temp, ds.tellp() );
}
void remove(uint64_t primary_key, uint64_t seconday_key, uint64_t tertiary_key) {
uint64_t temp[3] = { primary_key, seconday_key, tertiary_key };
remove_i64i64i64(_scope, TableName, temp);
}
private:
uint64_t _scope;
};
}
......@@ -61,5 +61,39 @@ extern "C" {
void send_deferred(uint32_t sender_id, time delay_until, char *serialized_transaction, size_t size);
/**
* access a copy of the currently executing transaction
*
* @param buffer - a buffer to write the current transaction to
* @param size - the size of the buffer
* @return the size of the transaction written to the buffer
*/
size_t read_transaction(char *buffer, size_t size);
/**
* get the size of the currently executing transaction
* @return
*/
size_t transaction_size();
/**
* get the block number used for TAPOS on the currently executing transaction
*
* @return
*/
int tapos_block_num();
/**
* get the block prefix used for TAPOS on the currently executing transaction
* @return
*/
int tapos_block_prefix();
/**
* get the expiration of the currently executing transaction
* @return
*/
time expiration();
///@ } transactioncapi
}
......@@ -285,14 +285,6 @@ void apply_exchange_cancel_sell( order_id order ) {
} // namespace exchange
extern "C" {
void init() {
/*
setAuthority( "currencya", "transfer", "anyone" );
setAuthority( "currencyb", "transfer", "anyone" );
registerHandler( "apply", "currencya", "transfer" );
registerHandler( "apply", "currencyb", "transfer" );
*/
}
// void validate( uint64_t code, uint64_t action ) { }
// void precondition( uint64_t code, uint64_t action ) { }
......
file(GLOB ABI_FILES "*.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_target(identity "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(test)
{
"types": [{
"new_type_name": "account_name",
"type": "name"
},{
"new_type_name": "identity_name",
"type": "name"
},{
"new_type_name": "property_name",
"type": "name"
}
],
"structs": [{
"name": "create",
"base": "",
"fields": [
{"name":"creator", "type":"account_name"},
{"name":"identity", "type":"uint64"}
]
},{
"name": "certvalue",
"base": "",
"fields": [
{"name":"property", "type":"name"},
{"name":"type", "type":"string"},
{"name":"data", "type":"uint8[]"},
{"name":"memo", "type":"string"},
{"name":"confidence", "type":"uint8"},
]
},{
"name": "certprop",
"base": "",
"fields": [
{"name":"bill_storage_to", "type":"account_name"},
{"name":"certifier", "type":"account_name"},
{"name":"identity", "type":"uint64"},
{"name":"value", "type":"certvalue[]"}
]
},{
"name": "settrust",
"base": "",
"fields": [
{"name":"trustor", "type":"account_name"},
{"name":"trusting", "type":"account_name"},
{"name":"trust", "type":"uint8"}
]
},{
"name": "certrow",
"base": "",
"fields": [
{"name":"property", "type":"property_name"},
{"name":"trusted", "type":"uint64"},
{"name":"certifier", "type":"account_name"},
{"name":"confidence", "type":"uint8"},
{"name":"type", "type":"string"},
{"name":"data", "type":"uint8[]"}
]
},{
"name": "identrow",
"base": "",
"fields": [
{"name":"identity", "type":"uint64"},
{"name":"creator", "type":"account_name"}
]
},{
"name": "trustrow",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"trusted", "type":"uint8"}
]
},{
"name": "accountrow",
"base": "",
"fields": [
{"name":"account", "type":"account_name"}
]
}
],
"actions": [{
"name": "create",
"type": "create"
},{
"name": "certprop",
"type": "certprop"
},{
"name": "settrust",
"type": "settrust"
}
],
"tables": [{
"name": "certs",
"type": "certrow",
"index_type": "i64i64i64",
"key_names" : [
"property",
"trusted",
"certifier"
],
" key_types": [
"uint64",
"uint64",
"uint64"
]
},{
"name": "idents",
"type": "identrow",
"index_type": "i64",
"key_names" : [ "identity" ],
"key_types": [ "uint64" ]
},{
"name": "trust",
"type": "trustrow",
"index_type": "i64",
"key_names" : [ "account" ],
"key_types": [ "account_name" ]
}
]
}
#include "identity.hpp"
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
identity::contract< N(identity) >::apply( code, action );
}
}
#pragma once
#include <eosiolib/chain.h>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/table.hpp>
#include <eosiolib/vector.hpp>
#include <eosiolib/string.hpp>
namespace identity {
using eosio::action_meta;
using eosio::table_i64i64i64;
using eosio::table64;
using eosio::string;
using eosio::vector;
/**
* This contract maintains a graph database of certified statements about an
* identity. An identity is separated from the concept of an account because
* the mapping of identity to accounts is subject to community consensus.
*
* Some use cases need a global source of trust, this trust rooted in the voter
* who selects block producers. A block producer's opinion is "trusted" and so
* is the opinion of anyone the block producer marks as "trusted".
*
* When a block producer is voted out the implicit trust in every certification
* they made or those they trusted made is removed. All users are liable for
* making false certifications.
*
* An account needs to claim the identity and a trusted account must certify the
* claim.
*
* Data for an identity is stored:
*
* DeployToAccount / identity / certs / [property, trusted, certifier] => value
*
* Questions database is designed to answer:
*
* 1. has $identity.$unique been certified a "trusted" certifier
* 2. has $identity.$property been certified by $account
* 3. has $identity.$trusted been certified by a "trusted" certifier
* 4. what account has authority to speak on behalf of identity?
* - for each trusted owner certification
* check to see if the account has claimed it
*
* 5. what identity does account have authority to speak on behalf?
* - check what identity the account has self certified owner
* - verify that a trusted certifier has confirmed owner
*
* This database structure enables parallel opeartions on independent identities.
*
* When an account certs a property we check to see if that
*/
template<uint64_t DeployToAccount>
class contract {
public:
static const uint64_t code = DeployToAccount;
typedef uint64_t identity_name;
typedef uint64_t property_name;
typedef uint64_t property_type_name;
/**
* This action create a new globally unique 64 bit identifier,
* to minimize collisions each account is automatically assigned
* a 32 bit identity prefix based upon hash(account_name) ^ hash(tapos).
*
* With this method no two accounts are likely to be assigned the same
* 32 bit prefix consistantly due to the constantly changing tapos. This prevents
* abuse of 'creator' selection to generate intentional conflicts with other users.
*
* The creator can determine the last 32 bits using an algorithm of their choice. We
* presume the creator's algorithm can avoid collisions with itself.
*
* Even if two accounts get a collision in first 32 bits, a proper creator algorithm
* should generate randomness in last 32 bits that will minimize collisions. In event
* of collision transaction will fail and creator can try again.
*
* A 64 bit identity is used because the key is used frequently and it makes for more
* effecient tables/scopes/etc.
*/
struct create : public action_meta< code, N(create) >
{
account_name creator;
uint64_t identity = 0; ///< first 32 bits determinsitically derived from creator and tapos
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const create& c ){
return ds << c.creator << c.identity;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, create& c ){
return ds >> c.creator >> c.identity;
}
};
struct certvalue {
property_name property; ///< name of property, base32 encoded i64
string type; ///< defines type serialized in data
vector<char> data; ///<
string memo; ///< meta data documenting basis of certification
uint8_t confidence = 1; ///< used to define liability for lies,
/// 0 to delete
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const certvalue& c ){
return ds << c.property << c.type << c.data << c.memo << c.confidence;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, certvalue& c ){
return ds >> c.property >> c.type >> c.data >> c.memo >> c.confidence;
}
};
struct certprop : public action_meta< code, N(certprop) >
{
account_name bill_storage_to; ///< account which is paying for storage
account_name certifier;
identity_name identity;
vector<certvalue> values;
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const certprop& c ){
return ds << c.bill_storage_to << c.certifier << c.identity << c.values;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, certprop& c ){
return ds >> c.bill_storage_to >> c.certifier >> c.identity >> c.values;
}
};
struct settrust : public action_meta< code, N(settrust) >
{
account_name trustor; ///< the account authorizing the trust
account_name trusting; ///< the account receiving the trust
uint8_t trust = 0; /// 0 to remove, -1 to mark untrusted, 1 to mark trusted
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const settrust& c ){
return ds << c.trustor << c.trusting << c.trust;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, settrust& c ){
return ds >> c.trustor >> c.trusting >> c.trust;
}
};
/**
* Defines an object in an i64i64i64 table
*/
struct certrow {
property_name property;
uint64_t trusted;
account_name certifier;
uint8_t confidence = 0;
string type;
vector<char> data;
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const certrow& r ){
return ds << r.property << r.trusted << r.certifier << r.confidence << r.type << r.data;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, certrow& r ){
return ds >> r.property >> r.trusted >> r.certifier >> r.confidence >> r.type >> r.data;
}
};
struct identrow {
uint64_t identity;
account_name creator;
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const identrow& r ){
return ds << r.identity << r.creator;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, identrow& r ){
return ds >> r.identity >> r.creator;
}
};
struct trustrow {
account_name account;
uint8_t trusted;
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const trustrow& r ){
return ds << r.account << r.trusted;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, trustrow& r ){
return ds >> r.account >> r.trusted;
}
};
typedef table_i64i64i64<code, N(certs), certrow> certs_table;
typedef table64<code, N(ident), identrow> idents_table;
typedef table64<code, N(account), identity_name> accounts_table;
typedef table64<code, N(trust), trustrow> trust_table;
static identity_name get_claimed_identity( account_name acnt ) {
return accounts_table::get_or_default(acnt, 0);
}
static account_name get_owner_for_identity( identity_name ident ) {
// for each trusted owner certification
// check to see if the certification is still trusted
// check to see if the account has claimed it
certs_table certs( ident );
certrow row;
bool ok = certs.primary_lower_bound(row, N(owner), 1, 0);
while (ok && row.property == N(owner) && row.trusted) {
if (sizeof(account_name) == row.data.size()) {
account_name account = *reinterpret_cast<account_name*>(row.data.data());
if (ident == get_claimed_identity(account)) {
if (is_trusted(row.certifier) ) {
// the certifier is still trusted
return account;
} else if (DeployToAccount == current_receiver()){
//the certifier is no longer trusted, need to unset the flag
row.trusted = 0;
certs.store( row, 0 ); //assuming 0 means bill to the same account
} else {
// the certifier is no longer trusted, but the code runs in read-only mode
}
}
} else {
// bad row - skip it
}
ok = certs.next_primary(row, row);
}
// trusted certification not found
// let's see if some of untrusted certifications became trusted
ok = certs.primary_lower_bound(row, N(owner), 0, 0);
while (ok && row.property == N(owner) && !row.trusted) {
if (sizeof(account_name) == row.data.size()) {
account_name account = *reinterpret_cast<account_name*>(row.data.data());
if (ident == get_claimed_identity(account) && is_trusted(row.certifier)) {
// the certifier became trusted, need to set the flag
row.trusted = 1;
certs.store( row, 0 ); //assuming 0 means bill to the same account
return *reinterpret_cast<account_name*>(row.data.data());
}
} else {
// bad row - skip it
}
ok = certs.next_primary(row, row);
}
return 0;
}
static identity_name get_identity_for_account( account_name acnt ) {
// check what identity the account has self certified owner
// verify that a trusted certifier has confirmed owner
auto identity = get_claimed_identity(acnt);
return (identity != 0 && acnt == get_owner_for_identity(identity)) ? identity : 0;
}
static bool is_trusted_by( account_name trusted, account_name by ) {
trustrow def;
def.trusted = 0;
trustrow row = trust_table::get_or_default( trusted, by, def );
return def.trusted;
}
static bool is_trusted( account_name acnt ) {
account_name active_producers[21];
get_active_producers( active_producers, sizeof(active_producers) );
for( const auto& n : active_producers ) {
if( n == acnt )
return true;
}
for( const auto& n : active_producers ) {
if( is_trusted_by( acnt, n ) )
return true;
}
return false;
}
static void on( const settrust& t ) {
require_auth( t.trustor );
require_recipient( t.trusting );
if( t.trust != 0 ) {
trustrow row{ .account = t.trusting,
.trusted = t.trust };
trust_table::set( row, t.trustor );
} else {
trustrow row{ .account = t.trusting,
.trusted = t.trust };
trust_table::remove( row.account, t.trustor );
}
}
static void on( const create& c ) {
require_auth( c.creator );
assert( !idents_table::exists( c.identity ), "identity already exists" );
assert( c.identity != 0, "identity=0 is not allowed" );
idents_table::set( identrow{ .identity = c.identity,
.creator = c.creator } );
}
static void on( const certprop& cert ) {
require_auth( cert.certifier );
if( cert.bill_storage_to != cert.certifier )
require_auth( cert.bill_storage_to );
assert( idents_table::exists( cert.identity ), "identity does not exist" );
/// the table exists in the scope of the identity
certs_table certs( cert.identity );
for( const auto& value : cert.values ) {
if (value.confidence) {
certrow row;
row.property = value.property;
row.trusted = is_trusted( cert.certifier );
row.certifier = cert.certifier;
row.confidence = value.confidence;
assert(value.type.get_size() <= 32, "certrow::type shouldn't be longer than 32 bytes");
row.type = value.type;
row.data = value.data;
certs.store( row, cert.bill_storage_to );
//remove row with different "trusted" value
certs.remove(value.property, !row.trusted, cert.certifier);
//special handling for owner
if (value.property == N(owner)) {
assert(sizeof(account_name) == value.data.size(), "data size doesn't match account_name size");
account_name acnt = *reinterpret_cast<const account_name*>(value.data.data());
accounts_table::set( acnt, cert.identity );
}
} else {
//remove both tursted and untrusted because we cannot now if it was trusted back at creation time
certs.remove(value.property, 0, cert.certifier);
certs.remove(value.property, 1, cert.certifier);
//special handling for owner
if (value.property == N(owner)) {
assert(sizeof(account_name) == value.data.size(), "data size doesn't match account_name size");
account_name acnt = *reinterpret_cast<const account_name*>(value.data.data());
accounts_table::remove( acnt, cert.identity );
}
}
}
}
static void apply( account_name c, action_name act) {
eosio::dispatch<contract, create, certprop, settrust>(c,act);
}
};
} /// namespace identity
set(ABI_FILES "identity_test.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_target(identity_test "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR})
{
"types": [{
"new_type_name": "account_name",
"type": "name"
},{
"new_type_name": "identity_name",
"type": "name"
}
],
"structs": [{
"name": "getowner",
"base": "",
"fields": [
{"name":"identity", "type":"uint64"}
]
},{
"name": "getidentity",
"base": "",
"fields": [
{"name":"account", "type":"account_name"}
]
}
],
"actions": [{
"name": "getowner",
"type": "getowner"
},{
"name": "getidentity",
"type": "getidentity"
}
],
"tables": [
]
}
#include <eosiolib/chain.h>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/singleton.hpp>
#include <eosiolib/table.hpp>
#include <eosiolib/vector.hpp>
#include <identity/identity.hpp>
namespace identity_test {
using eosio::action_meta;
using eosio::singleton;
using eosio::string;
using eosio::vector;
class contract {
public:
static const uint64_t code = N(identitytest);
typedef identity::contract< N(identity) > identity_contract;
typedef identity_contract::identity_name identity_name;
typedef identity_contract::property_name property_name;
struct get_owner_for_identity : public action_meta< code, N(getowner) >
{
uint64_t identity;
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const get_owner_for_identity& c ){
return ds << c.identity;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, get_owner_for_identity& c ){
return ds >> c.identity;
}
};
struct get_identity_for_account : public action_meta< code, N(getidentity) >
{
account_name account ;
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const get_identity_for_account& c ){
return ds << c.account;
}
template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, get_identity_for_account& c ){
return ds >> c.account;
}
};
typedef singleton<code, N(result), uint64_t> result_table;
static void on( const get_owner_for_identity& c ) {
account_name owner = identity_contract::get_owner_for_identity(c.identity);
result_table::set(owner, 0); //use scope = 0 for simplicity
}
static void on( const get_identity_for_account& c ) {
identity_name idnt = identity_contract::get_identity_for_account(c.account);
result_table::set(idnt, 0); //use scope = 0 for simplicity
}
static void apply( account_name c, action_name act) {
eosio::dispatch<contract, get_owner_for_identity, get_identity_for_account>(c,act);
}
};
} /// namespace identity
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
identity_test::contract::apply( code, action );
}
}
......@@ -40,9 +40,6 @@ namespace infinite {
using namespace infinite;
extern "C" {
void init() {
store_account( N(currency), account( currency_tokens(1000ll*1000ll*1000ll) ) );
}
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
......
file(GLOB ABI_FILES "*.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_target(noop "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR})
{
"types": [{
"new_type_name": "account_name",
"type": "name"
}
],
"structs": [{
"name": "anyaction",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"type", "type":"string"},
{"name":"data", "type":"string"}
]
}
],
"actions": [{
"name":"anyaction",
"type":"anyaction"
}
],
"tables": []
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <noop/noop.hpp>
namespace noop {
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
eosio::dispatch<noop, noop::anyaction>(code, action);
}
}
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/eosio.hpp>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/string.hpp>
using namespace eosio;
namespace noop {
/**
noop contract
All it does is require sender authorization.
Actions: anyaction
*/
class noop {
public:
ACTION(N(noop), anyaction) {
anyaction() { }
anyaction(account_name f, const string& t, const string& d): from(f), type(t), data(d) { }
account_name from;
string type;
string data;
EOSLIB_SERIALIZE(anyaction, (from)(type)(data))
};
static void on(const anyaction& act)
{
require_auth(act.from);
}
};
} /// noop
......@@ -60,8 +60,6 @@ using namespace proxy;
using namespace eosio;
extern "C" {
void init() {
}
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
......
......@@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/db.hpp>
namespace proxy {
......
......@@ -10,9 +10,6 @@
#include <eosiolib/raw.hpp>
extern "C" {
void init() {
}
void apply( uint64_t code, uint64_t action ) {
if( code == N(simpledb) ) {
......
......@@ -10,13 +10,6 @@
*/
extern "C" {
/**
* This method is called once when the contract is published or updated.
*/
void init() {
eosio::print( "Init World!\n" );
}
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
eosio::print( "Hello World: ", eosio::name(code), "->", eosio::name(action), "\n" );
......
......@@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/db.hpp>
......@@ -100,10 +100,6 @@ namespace TOKEN_NAME {
using namespace TOKEN_NAME;
extern "C" {
void init() {
// How do we initialize the storage capacity? By how much here?
accounts::store( account( storage_tokens(1000ll*1000ll*1000ll) ), N(storage) );
}
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
......
......@@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
#include "test_api.hpp"
//#include "test_account.cpp"
......
......@@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/eosio.hpp>
#include "test_api.hpp"
......
......@@ -182,12 +182,6 @@ namespace tic_tac_toe {
*/
extern "C" {
/**
* This method is called once when the contract is published or updated.
*/
void init() {
}
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
if (code == N(tic.tac.toe)) {
......
......@@ -15,127 +15,127 @@
"name": "inita",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initb",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initc",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initd",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "inite",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initf",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initg",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "inith",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initi",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initj",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initk",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initl",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initm",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initn",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "inito",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initp",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initq",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initr",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "inits",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initt",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
},{
"name": "initu",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.0000 EOS"
"liquid_balance": "1000000.0000 EOS",
"staking_balance": "100.0000 EOS"
}],
"initial_producers": [{
......
......@@ -9,6 +9,7 @@ add_library( eosio_chain
block.cpp
wast_to_wasm.cpp
wasm_interface.cpp
wasm_eosio_constraints.cpp
apply_context.cpp
rate_limiting.cpp
......@@ -22,20 +23,19 @@ add_library( eosio_chain
chain_controller.cpp
contracts/eosio_contract.cpp
contracts/producer_objects.cpp
contracts/staked_balance_objects.cpp
contracts/chain_initializer.cpp
contracts/genesis_state.cpp
contracts/abi_serializer.cpp
${HEADERS}
)
transaction_metadata.cpp)
target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime )
target_include_directories( eosio_chain
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include"
"${CMAKE_BINARY_DIR}/contracts"
)
if(MSVC)
......
......@@ -17,6 +17,7 @@ void apply_context::exec_one()
(*native)(*this);
} else {
const auto &a = mutable_controller.get_database().get<account_object, by_name>(receiver);
privileged = a.privileged;
if (a.code.size() > 0) {
// get code from cache
......@@ -101,7 +102,7 @@ void apply_context::exec()
}
for( uint32_t i = 0; i < _inline_actions.size(); ++i ) {
apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta);
apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta, _checktime_limit);
ncontext.exec();
append_results(move(ncontext.results));
}
......@@ -233,4 +234,29 @@ vector<account_name> apply_context::get_active_producers() const {
return accounts;
}
void apply_context::checktime_start() {
_checktime_start = fc::time_point::now();
}
void apply_context::checktime() const {
if ((fc::time_point::now() - _checktime_start).count() > _checktime_limit) {
throw checktime_exceeded();
}
}
const bytes& apply_context::get_packed_transaction() {
if( !trx_meta.packed_trx.size() ) {
if (_cached_trx.empty()) {
auto size = fc::raw::pack_size(trx_meta.trx());
_cached_trx.resize(size);
fc::datastream<char *> ds(_cached_trx.data(), size);
fc::raw::pack(ds, trx_meta.trx());
}
return _cached_trx;
}
return trx_meta.packed_trx;
}
} } /// eosio::chain
......@@ -11,30 +11,15 @@ namespace eosio { namespace chain {
typedef boost::multiprecision::int128_t int128_t;
uint8_t asset::decimals()const {
auto a = (const char*)&symbol;
return a[0];
}
void asset::set_decimals(uint8_t d){
auto a = (char*)&symbol;
a[0] = d;
return sym.decimals();
}
string asset::symbol_name()const {
auto a = (const char*)&symbol;
assert( a[7] == 0 );
return &a[1];
return sym.name();
}
int64_t asset::precision()const {
static int64_t table[] = {
1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000ll,
1000000000ll, 10000000000ll,
100000000000ll, 1000000000000ll,
10000000000000ll, 100000000000000ll
};
return table[ decimals() ];
return sym.precision();
}
string asset::to_string()const {
......@@ -49,118 +34,35 @@ string asset::to_string()const {
asset asset::from_string(const string& from)
{
try
{
string s = fc::trim( from );
auto space_pos = s.find( " " );
auto dot_pos = s.find( "." );
try {
string s = fc::trim(from);
auto dot_pos = s.find(".");
FC_ASSERT(dot_pos != string::npos, "dot missing in asset from string");
auto space_pos = s.find(" ", dot_pos);
FC_ASSERT(space_pos != string::npos, "space missing in asset from string");
asset result;
result.symbol = uint64_t(0);
auto sy = (char*)&result.symbol;
*sy = (char) dot_pos; // Mask due to undefined architecture behavior
auto intpart = s.substr( 0, dot_pos );
auto intpart = s.substr(0, dot_pos);
result.amount = fc::to_int64(intpart);
string fractpart;
if( dot_pos != string::npos )
{
auto fractpart = "1" + s.substr( dot_pos + 1, space_pos - dot_pos - 1 );
result.set_decimals( fractpart.size() - 1 );
string symbol_part;
if (dot_pos != string::npos && space_pos != string::npos) {
symbol_part = eosio::chain::to_string(space_pos - dot_pos - 1);
symbol_part += ',';
symbol_part += s.substr(space_pos + 1);
}
result.sym = symbol::from_string(symbol_part);
if (dot_pos != string::npos) {
auto fractpart = "1" + s.substr(dot_pos + 1, space_pos - dot_pos - 1);
result.amount *= int64_t(result.precision());
result.amount += int64_t(fc::to_int64(fractpart));
result.amount -= int64_t(result.precision());
}
auto symbol = s.substr( space_pos + 1 );
if( symbol.size() )
memcpy( sy+1, symbol.c_str(), std::min(symbol.size(),size_t(6)) );
return result;
}
FC_CAPTURE_LOG_AND_RETHROW( (from) )
}
bool operator == ( const price& a, const price& b )
{
if( std::tie( a.base.symbol, a.quote.symbol ) != std::tie( b.base.symbol, b.quote.symbol ) )
return false;
const auto amult = uint128_t( b.quote.amount ) * uint128_t(a.base.amount);
const auto bmult = uint128_t( a.quote.amount ) * uint128_t(b.base.amount);
return amult == bmult;
}
bool operator < ( const price& a, const price& b )
{
if( a.base.symbol < b.base.symbol ) return true;
if( a.base.symbol > b.base.symbol ) return false;
if( a.quote.symbol < b.quote.symbol ) return true;
if( a.quote.symbol > b.quote.symbol ) return false;
const auto amult = uint128_t( b.quote.amount ) * uint128_t(a.base.amount);
const auto bmult = uint128_t( a.quote.amount ) * uint128_t(b.base.amount);
return amult < bmult;
}
bool operator <= ( const price& a, const price& b )
{
return (a == b) || (a < b);
}
bool operator != ( const price& a, const price& b )
{
return !(a == b);
}
bool operator > ( const price& a, const price& b )
{
return !(a <= b);
}
bool operator >= ( const price& a, const price& b )
{
return !(a < b);
}
asset operator * ( const asset& a, const price& b )
{
if( a.symbol_name() == b.base.symbol_name() )
{
FC_ASSERT( static_cast<int64_t>(b.base.amount) > 0 );
auto result = (uint128_t(a.amount) * uint128_t(b.quote.amount))/uint128_t(b.base.amount);
return asset( int64_t(result), b.quote.symbol );
}
else if( a.symbol_name() == b.quote.symbol_name() )
{
FC_ASSERT( static_cast<int64_t>(b.quote.amount) > 0 );
auto result = (uint128_t(a.amount) *uint128_t(b.base.amount))/uint128_t(b.quote.amount);
return asset( int64_t(result), b.base.symbol );
}
FC_THROW_EXCEPTION( fc::assert_exception, "invalid asset * price", ("asset",a)("price",b) );
}
price operator / ( const asset& base, const asset& quote )
try {
FC_ASSERT( base.symbol_name() != quote.symbol_name() );
return price{ base, quote };
} FC_CAPTURE_AND_RETHROW( (base)(quote) )
price price::max( asset_symbol base, asset_symbol quote ) { return asset( share_type(EOS_MAX_SHARE_SUPPLY), base ) / asset( share_type(1), quote); }
price price::min( asset_symbol base, asset_symbol quote ) { return asset( 1, base ) / asset( EOS_MAX_SHARE_SUPPLY, quote); }
bool price::is_null() const { return *this == price(); }
void price::validate() const
try {
FC_ASSERT( base.amount > share_type(0) );
FC_ASSERT( quote.amount > share_type(0) );
FC_ASSERT( base.symbol_name() != quote.symbol_name() );
} FC_CAPTURE_AND_RETHROW( (base)(quote) )
} } // eosio::types
\ No newline at end of file
} } // eosio::types
......@@ -52,7 +52,7 @@ namespace eosio { namespace chain {
ids.reserve(input_transactions.size());
for( const auto& t : input_transactions )
ids.emplace_back( t.id() );
ids.emplace_back( t.get_transaction().id() );
return merkle( std::move(ids) );
}
......
......@@ -52,9 +52,11 @@ namespace eosio { namespace chain { namespace contracts {
//public_key.hpp
built_in_types.emplace("public_key", pack_unpack<public_key_type>());
//symbol.hpp
built_in_types.emplace("symbol", pack_unpack<symbol>());
//asset.hpp
built_in_types.emplace("asset", pack_unpack<asset>());
built_in_types.emplace("price", pack_unpack<price>());
//native.hpp
built_in_types.emplace("string", pack_unpack<string>());
......@@ -96,7 +98,6 @@ namespace eosio { namespace chain { namespace contracts {
built_in_types.emplace("action_def", pack_unpack<action_def>());
built_in_types.emplace("table_def", pack_unpack<table_def>());
built_in_types.emplace("abi_def", pack_unpack<abi_def>());
built_in_types.emplace("nonce", pack_unpack<nonce>());
}
void abi_serializer::set_abi(const abi_def& abi) {
......
......@@ -3,12 +3,17 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/contracts/chain_initializer.hpp>
#include <eosio/chain/contracts/objects.hpp>
#include <eosio/chain/contracts/eos_contract.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio.system/eosio.system.wast.hpp>
#include <eosio.system/eosio.system.abi.hpp>
#include <fc/io/json.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
......@@ -23,36 +28,25 @@ chain_config chain_initializer::get_chain_start_configuration() {
return genesis.initial_configuration;
}
producer_schedule_type chain_initializer::get_chain_start_producers() {
producer_schedule_type chain_initializer::get_chain_start_producers() {
producer_schedule_type result;
std::transform(genesis.initial_producers.begin(), genesis.initial_producers.end(), result.producers.begin(),
[](const auto& p) { return producer_key{p.owner_name,p.block_signing_key}; });
result.producers.push_back( {config::system_account_name, genesis.initial_key} );
idump((result));
return result;
}
void chain_initializer::register_types(chain_controller& chain, chainbase::database& db) {
// Install the native contract's indexes; we can't do anything until our objects are recognized
db.add_index<staked_balance_multi_index>();
db.add_index<producer_votes_multi_index>();
#define SET_APP_HANDLER( contract, scope, action, nspace ) \
chain._set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(contracts::apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )
SET_APP_HANDLER( eosio, eosio, setproducer, eosio );
SET_APP_HANDLER( eosio, eosio, newaccount, eosio );
SET_APP_HANDLER( eosio, eosio, transfer, eosio );
SET_APP_HANDLER( eosio, eosio, lock, eosio );
SET_APP_HANDLER( eosio, eosio, claim, eosio );
SET_APP_HANDLER( eosio, eosio, unlock, eosio );
SET_APP_HANDLER( eosio, eosio, okproducer, eosio );
SET_APP_HANDLER( eosio, eosio, setproxy, eosio );
SET_APP_HANDLER( eosio, eosio, setcode, eosio );
SET_APP_HANDLER( eosio, eosio, setabi, eosio );
SET_APP_HANDLER( eosio, eosio, updateauth, eosio );
SET_APP_HANDLER( eosio, eosio, deleteauth, eosio );
SET_APP_HANDLER( eosio, eosio, linkauth, eosio );
SET_APP_HANDLER( eosio, eosio, unlinkauth, eosio );
SET_APP_HANDLER( eosio, eosio, nonce, eosio );
SET_APP_HANDLER( eosio, eosio, onerror, eosio );
SET_APP_HANDLER( eosio, eosio, postrecovery, eosio );
SET_APP_HANDLER( eosio, eosio, passrecovery, eosio );
......@@ -66,13 +60,6 @@ abi_def chain_initializer::eos_contract_abi()
eos_abi.types.push_back( type_def{"account_name","name"} );
eos_abi.types.push_back( type_def{"share_type","int64"} );
eos_abi.types.push_back( type_def{"onerror","bytes"} );
eos_abi.actions.push_back( action_def{name("transfer"), "transfer"} );
eos_abi.actions.push_back( action_def{name("lock"), "lock"} );
eos_abi.actions.push_back( action_def{name("unlock"), "unlock"} );
eos_abi.actions.push_back( action_def{name("claim"), "claim"} );
eos_abi.actions.push_back( action_def{name("okproducer"), "okproducer"} );
eos_abi.actions.push_back( action_def{name("setproducer"), "setproducer"} );
eos_abi.actions.push_back( action_def{name("setproxy"), "setproxy"} );
eos_abi.actions.push_back( action_def{name("setcode"), "setcode"} );
eos_abi.actions.push_back( action_def{name("setabi"), "setabi"} );
eos_abi.actions.push_back( action_def{name("linkauth"), "linkauth"} );
......@@ -84,62 +71,9 @@ abi_def chain_initializer::eos_contract_abi()
eos_abi.actions.push_back( action_def{name("passrecovery"), "passrecovery"} );
eos_abi.actions.push_back( action_def{name("vetorecovery"), "vetorecovery"} );
eos_abi.actions.push_back( action_def{name("onerror"), "onerror"} );
eos_abi.actions.push_back( action_def{name("nonce"), "nonce"} );
// ACTION PAYLOADS
eos_abi.structs.emplace_back( struct_def {
"transfer", "", {
{"from", "account_name"},
{"to", "account_name"},
{"amount", "uint64"},
{"memo", "string"},
}
});
eos_abi.structs.emplace_back( struct_def {
"lock", "", {
{"from", "account_name"},
{"to", "account_name"},
{"amount", "share_type"},
}
});
eos_abi.structs.emplace_back( struct_def {
"unlock", "", {
{"account", "account_name"},
{"amount", "share_type"},
}
});
eos_abi.structs.emplace_back( struct_def {
"claim", "", {
{"account", "account_name"},
{"amount", "share_type"},
}
});
eos_abi.structs.emplace_back( struct_def {
"okproducer", "", {
{"voter", "account_name"},
{"producer", "account_name"},
{"approve", "int8"},
}
});
eos_abi.structs.emplace_back( struct_def {
"setproducer", "", {
{"name", "account_name"},
{"key", "public_key"},
{"configuration", "chain_config"},
}
});
eos_abi.structs.emplace_back( struct_def {
"setproxy", "", {
{"stakeholder", "account_name"},
{"proxy", "account_name"},
}
});
eos_abi.structs.emplace_back( struct_def {
"setcode", "", {
......@@ -197,7 +131,6 @@ abi_def chain_initializer::eos_contract_abi()
{"owner", "authority"},
{"active", "authority"},
{"recovery", "authority"},
{"deposit", "asset"},
}
});
......@@ -221,12 +154,6 @@ abi_def chain_initializer::eos_contract_abi()
}
});
eos_abi.structs.emplace_back( struct_def {
"nonce", "", {
{"value", "name"}
}
});
// DATABASE RECORDS
eos_abi.structs.emplace_back( struct_def {
"account", "", {
......@@ -275,57 +202,76 @@ std::vector<action> chain_initializer::prepare_database( chain_controller& chain
std::vector<action> messages_to_process;
/// Create the native contract accounts manually; sadly, we can't run their contracts to make them create themselves
auto create_native_account = [this, &db](account_name name, auto liquid_balance) {
auto create_native_account = [this, &db](account_name name) {
db.create<account_object>([this, &name](account_object& a) {
a.name = name;
a.creation_date = genesis.initial_timestamp;
a.privileged = true;
if( name == config::system_account_name ) {
a.set_abi(eos_contract_abi());
}
});
const auto& owner = db.create<permission_object>([&name](permission_object& p) {
const auto& owner = db.create<permission_object>([&](permission_object& p) {
p.owner = name;
p.name = "owner";
p.auth.threshold = 1;
p.auth.keys.push_back( key_weight{ .key = genesis.initial_key, .weight = 1 } );
});
db.create<permission_object>([&name, &owner](permission_object& p) {
db.create<permission_object>([&](permission_object& p) {
p.owner = name;
p.parent = owner.id;
p.name = "active";
p.auth.threshold = 1;
p.auth.keys.push_back( key_weight{ .key = genesis.initial_key, .weight = 1 } );
});
db.create<bandwidth_usage_object>([&](auto& sb) {
sb.owner = name;
sb.net_weight = -1;
sb.cpu_weight = -1;
sb.db_reserved_capacity = -1;
});
db.create<producer_object>( [&]( auto& pro ) {
pro.owner = config::system_account_name;
pro.signing_key = genesis.initial_key;
});
intialize_eosio_tokens(db, name, liquid_balance);
db.create<staked_balance_object>([&](auto& sb) { sb.owner_name = name; });
db.create<bandwidth_usage_object>([&](auto& sb) { sb.owner = name; });
};
create_native_account(config::system_account_name, config::initial_token_supply);
create_native_account(config::system_account_name);
// Queue up messages which will run contracts to create the initial accounts
auto init_eosio_sytem = genesis_state_type::initial_account_type(name(config::eosio_system_account_name).to_string(), 0, 0, genesis.eosio_system_key, genesis.eosio_system_key);
genesis.initial_accounts.emplace_back(move(init_eosio_sytem));
for (const auto& acct : genesis.initial_accounts) {
action message( {{config::system_account_name, config::active_name}},
newaccount{ config::system_account_name, acct.name,
authority(acct.owner_key),
authority(acct.active_key),
authority(acct.owner_key),
acct.staking_balance});
authority(acct.owner_key)
});
messages_to_process.emplace_back(move(message));
if (acct.liquid_balance > 0) {
message = action( {{config::system_account_name, config::active_name}},
transfer{ .from = config::system_account_name, .to = acct.name,
.amount = acct.liquid_balance.amount, .memo = "Genesis Allocation"});
messages_to_process.emplace_back(move(message));
}
}
// Create initial producers
auto create_producer = boost::adaptors::transformed([config = genesis.initial_configuration](const auto& p) {
return action( {{p.owner_name, config::active_name}},
setproducer(p.owner_name, p.block_signing_key, config));
});
boost::copy(genesis.initial_producers | create_producer, std::back_inserter(messages_to_process));
// Create initial contracts eosio.system
auto wasm = wast_to_wasm(eosio_system_wast);
action eosio_system_setcode({{config::eosio_system_account_name, config::active_name}},
contracts::setcode{
.account = config::eosio_system_account_name,
.vmtype = 0,
.vmversion = 0,
.code = bytes(wasm.begin(), wasm.end())
});
auto abi = fc::json::from_string(eosio_system_abi).template as<contracts::abi_def>();
action eosio_system_setabi({{config::eosio_system_account_name, config::active_name}},
contracts::setabi{
.account = config::eosio_system_account_name,
.abi = abi
});
messages_to_process.emplace_back(move(eosio_system_setcode));
messages_to_process.emplace_back(move(eosio_system_setabi));
// Create special accounts
auto create_special_account = [this, &db](account_name name, const auto& owner, const auto& active) {
......@@ -349,9 +295,7 @@ std::vector<action> chain_initializer::prepare_database( chain_controller& chain
auto empty_authority = authority(0, {}, {});
auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
for(auto& p : genesis.initial_producers) {
active_producers_authority.accounts.push_back({{p.owner_name, config::active_name}, 1});
}
active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});
create_special_account(config::nobody_account_name, empty_authority, empty_authority);
create_special_account(config::producers_account_name, empty_authority, active_producers_authority);
......
......@@ -15,8 +15,6 @@
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/producer_object.hpp>
......@@ -52,21 +50,6 @@ static void modify_eosio_balance( apply_context& context, const account_name& ac
context.store_record<key_value_object>(t_id, config::system_account_name, &key, (const char *)&balance, sizeof(balance));
}
share_type get_eosio_balance( const chainbase::database& db, const account_name &account ) {
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(config::system_account_name, account, N(currency)));
if (!t_id) {
return share_type(0);
}
const auto& idx = db.get_index<key_value_index, by_scope_primary>();
auto itr = idx.lower_bound(boost::make_tuple(t_id->id));
if ( itr == idx.end() || itr->t_id != t_id->id ) {
return share_type(0);
}
FC_ASSERT(itr->value.size() == sizeof(share_type), "Invalid data in EOSIO balance table");
return *reinterpret_cast<const share_type *>(itr->value.data());
}
void validate_authority_precondition( const apply_context& context, const authority& auth ) {
for(const auto& a : auth.accounts) {
......@@ -76,9 +59,7 @@ void validate_authority_precondition( const apply_context& context, const author
}
/**
* This method is called assuming precondition_system_newaccount succeeds and proceeds to
* deduct the balance of the account creator by deposit, this deposit is supposed to be
* credited to the staked balance the new account in the @staked contract.
* This method is called assuming precondition_system_newaccount succeeds a
*/
void apply_eosio_newaccount(apply_context& context) {
auto create = context.act.as<newaccount>();
......@@ -118,104 +99,10 @@ void apply_eosio_newaccount(apply_context& context) {
const auto& owner_permission = create_permission("owner", 0, std::move(create.owner));
create_permission("active", owner_permission.id, std::move(create.active));
share_type creator_balance = get_eosio_balance(context.db, create.creator);
EOS_ASSERT(creator_balance >= create.deposit.amount, action_validate_exception,
"Creator '${c}' has insufficient funds to make account creation deposit of ${a}",
("c", create.creator)("a", create.deposit));
modify_eosio_balance(context, create.creator, -create.deposit.amount);
const auto& sbo = context.mutable_db.create<staked_balance_object>([&]( staked_balance_object& sbo) {
sbo.owner_name = create.name;
sbo.staked_balance = 0;
});
sbo.stake_tokens( create.deposit.amount, context.mutable_db );
db.create<bandwidth_usage_object>([&]( auto& bu ) { bu.owner = create.name; });
} FC_CAPTURE_AND_RETHROW( (create) ) }
/**
*
* @ingroup native_eos
* @defgroup eos_eosio_transfer eosio::eos_transfer
*/
///@{
void apply_eosio_transfer(apply_context& context) {
auto transfer = context.act.as<contracts::transfer>();
try {
EOS_ASSERT(transfer.amount > 0, action_validate_exception, "Must transfer a positive amount");
context.require_write_lock(transfer.to);
context.require_write_lock(transfer.from);
context.require_authorization(transfer.from);
context.require_recipient(transfer.to);
context.require_recipient(transfer.from);
} FC_CAPTURE_AND_RETHROW((transfer))
try {
auto& db = context.mutable_db;
share_type from_balance = get_eosio_balance(db, transfer.from);
EOS_ASSERT(from_balance >= transfer.amount, action_validate_exception, "Insufficient Funds",
("from_balance", from_balance)("transfer.amount",transfer.amount));
modify_eosio_balance(context, transfer.from, - share_type(transfer.amount) );
modify_eosio_balance(context, transfer.to, share_type(transfer.amount) );
} FC_CAPTURE_AND_RETHROW( (transfer) )
}
///@}
/**
* Deduct the balance from the from account.
*/
void apply_eosio_lock(apply_context& context) {
auto lock = context.act.as<contracts::lock>();
EOS_ASSERT(lock.amount > 0, action_validate_exception, "Locked amount must be positive");
context.require_write_lock(lock.to);
context.require_write_lock(lock.from);
context.require_write_lock(config::system_account_name);
context.require_authorization(lock.from);
context.require_recipient(lock.to);
context.require_recipient(lock.from);
share_type locker_balance = get_eosio_balance(context.db, lock.from);
EOS_ASSERT( locker_balance >= lock.amount, action_validate_exception,
"Account ${a} lacks sufficient funds to lock ${amt} EOS", ("a", lock.from)("amt", lock.amount)("available",locker_balance) );
modify_eosio_balance(context, lock.from, -share_type(lock.amount));
const auto& balance = context.db.get<staked_balance_object, by_owner_name>(lock.to);
balance.stake_tokens(lock.amount, context.mutable_db);
}
void apply_eosio_unlock(apply_context& context) {
auto unlock = context.act.as<contracts::unlock>();
context.require_authorization(unlock.account);
EOS_ASSERT(unlock.amount >= 0, action_validate_exception, "Unlock amount cannot be negative");
const auto& balance = context.db.get<staked_balance_object, by_owner_name>(unlock.account);
EOS_ASSERT(balance.staked_balance >= unlock.amount, action_validate_exception,
"Insufficient locked funds to unlock ${a}", ("a", unlock.amount));
balance.begin_unstaking_tokens(unlock.amount, context.mutable_db);
}
void apply_eosio_setcode(apply_context& context) {
auto& db = context.mutable_db;
......@@ -238,12 +125,11 @@ void apply_eosio_setcode(apply_context& context) {
// Added resize(0) here to avoid bug in boost vector container
a.code.resize( 0 );
a.code.resize( act.code.size() );
a.last_code_update = context.controller.head_block_time();
memcpy( a.code.data(), act.code.data(), act.code.size() );
});
// make sure the code gets a chance to initialize itself
context.require_recipient(act.account);
}
void apply_eosio_setabi(apply_context& context) {
......@@ -263,148 +149,6 @@ void apply_eosio_setabi(apply_context& context) {
});
}
void apply_eosio_claim(apply_context& context) {
auto claim = context.act.as<contracts::claim>();
EOS_ASSERT(claim.amount > 0, action_validate_exception, "Claim amount must be positive");
context.require_authorization(claim.account);
auto balance = context.db.find<staked_balance_object, by_owner_name>(claim.account);
EOS_ASSERT(balance != nullptr, action_validate_exception,
"Could not find staked balance for ${name}", ("name", claim.account));
auto balance_release_time = balance->last_unstaking_time + fc::seconds(config::staked_balance_cooldown_sec);
auto now = context.controller.head_block_time();
EOS_ASSERT(now >= balance_release_time, action_validate_exception,
"Cannot claim balance until ${releaseDate}", ("releaseDate", balance_release_time));
EOS_ASSERT(balance->unstaking_balance >= claim.amount, action_validate_exception,
"Cannot claim ${claimAmount} as only ${available} is available for claim",
("claimAmount", claim.amount)("available", balance->unstaking_balance));
const auto& staked_balance = context.db.get<staked_balance_object, by_owner_name>(claim.account);
staked_balance.finish_unstaking_tokens(claim.amount, context.mutable_db);
modify_eosio_balance(context, claim.account, share_type(claim.amount));
}
void apply_eosio_setproducer(apply_context& context) {
auto update = context.act.as<setproducer>();
context.require_authorization(update.name);
EOS_ASSERT(update.name.good(), action_validate_exception, "Producer owner name cannot be empty");
auto& db = context.mutable_db;
auto producer = db.find<producer_object, by_owner>(update.name);
if (producer) {
EOS_ASSERT(producer->signing_key != update.key || producer->configuration != update.configuration,
action_validate_exception, "Producer's new settings may not be identical to old settings");
db.modify(*producer, [&](producer_object& p) {
p.signing_key = update.key;
p.configuration = update.configuration;
});
} else {
db.create<producer_object>([&](producer_object& p) {
p.owner = update.name;
p.signing_key = update.key;
p.configuration = update.configuration;
});
db.create<producer_votes_object>([&](producer_votes_object& pvo) {
pvo.owner_name = update.name;
});
}
}
void apply_eosio_okproducer(apply_context& context) {
auto approve = context.act.as<okproducer>();
EOS_ASSERT(approve.approve == 0 || approve.approve == 1, action_validate_exception,
"Unknown approval value: ${val}; must be either 0 or 1", ("val", approve.approve));
context.require_recipient(approve.voter);
context.require_recipient(approve.producer);
context.require_write_lock(config::system_account_name);
context.require_write_lock(approve.voter);
context.require_authorization(approve.voter);
auto& db = context.mutable_db;
const auto& producer = db.get<producer_votes_object, by_owner_name>(approve.producer);
const auto& voter = db.get<staked_balance_object, by_owner_name>(approve.voter);
EOS_ASSERT(voter.producer_votes.contains<producer_slate>(), action_validate_exception,
"Cannot approve producer; approving account '${name}' proxies its votes to '${proxy}'",
("name", voter.owner_name)("proxy", voter.producer_votes.get<account_name>()));
const auto& slate = voter.producer_votes.get<producer_slate>();
EOS_ASSERT(slate.size < config::max_producer_votes, action_validate_exception,
"Cannot approve producer; approved producer count is already at maximum");
if (approve.approve)
EOS_ASSERT(!slate.contains(producer.owner_name), action_validate_exception,
"Cannot add approval to producer '${name}'; producer is already approved",
("name", producer.owner_name));
else
EOS_ASSERT(slate.contains(producer.owner_name), action_validate_exception,
"Cannot remove approval from producer '${name}'; producer is not approved",
("name", producer.owner_name));
auto total_voting_stake = voter.staked_balance;
// Add/remove votes from producer
db.modify(producer, [approve = approve.approve, total_voting_stake](producer_votes_object& pvo) {
if (approve)
pvo.update_votes(total_voting_stake);
else
pvo.update_votes(-total_voting_stake);
});
// Add/remove producer from voter's approved producer list
db.modify(voter, [&approve, producer = producer.owner_name](staked_balance_object& sbo) {
auto& slate = sbo.producer_votes.get<producer_slate>();
if (approve.approve)
slate.add(producer);
else
slate.remove(producer);
});
}
void apply_eosio_setproxy(apply_context& context) {
auto svp = context.act.as<setproxy>();
FC_ASSERT( !"Not Implemented Yet" );
/*
context.require_authorization( spv.stakeholder );
context.require_recipient(svp.stakeholder);
context.require_recipient(svp.proxy);
auto& db = context.mutable_db;
const auto& proxy = db.get<proxy_vote_object, by_target_name>(context.act.recipient(svp.proxy));
const auto& balance = db.get<staked_balance_object, by_owner_name>(context.act.recipient(svp.stakeholder));
auto proxy = db.find<proxy_vote_object, by_target_name>(context.act.recipient(svp.proxy));
if (svp.proxy != svp.stakeholder) {
// We are enabling proxying to svp.proxy
proxy.add_proxy_source(context.act.recipient(svp.stakeholder), balance.staked_balance, db);
db.modify(balance, [target = proxy.proxy_target](staked_balance_object& sbo) { sbo.producer_votes = target; });
} else {
// We are disabling proxying to balance.producer_votes.get<account_name>()
proxy.remove_proxy_source(context.act.recipient(svp.stakeholder), balance.staked_balance, db);
db.modify(balance, [](staked_balance_object& sbo) { sbo.producer_votes = producer_slate{}; });
}
*/
}
void apply_eosio_updateauth(apply_context& context) {
context.require_write_lock( config::eosio_auth_scope );
......@@ -549,9 +293,6 @@ void apply_eosio_unlinkauth(apply_context& context) {
db.remove(*link);
}
void apply_eosio_nonce(apply_context&) {
/// do nothing
}
void apply_eosio_onerror(apply_context& context) {
assert(context.trx_meta.sender);
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/producer_object.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/algorithm_ext.hpp>
namespace eosio { namespace chain { namespace contracts {
} } } // namespace eosio::chain::contracts
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <boost/range/algorithm/for_each.hpp>
namespace eosio { namespace chain { namespace contracts {
void staked_balance_object::stake_tokens(share_type new_stake, chainbase::database& db) const {
// Update the staked balance
db.modify(*this, [&new_stake](staked_balance_object& sbo) {
sbo.staked_balance += new_stake;
});
db.modify( db.get<dynamic_global_property_object>(), [&]( auto& dgpo ){
dgpo.total_staked_tokens += new_stake;
});
propagate_votes(new_stake, db);
}
void staked_balance_object::begin_unstaking_tokens(share_type amount, chainbase::database& db) const {
// Remember there might be stake left over from a previous, uncompleted unstaking in unstaking_balance
auto delta_stake = unstaking_balance - amount;
// Update actual stake balance and invariants around it
stake_tokens(delta_stake, db);
// Update stats for unstaking process
db.modify(*this, [&amount, &db](staked_balance_object& sbo) {
sbo.unstaking_balance = amount;
sbo.last_unstaking_time = db.get(dynamic_global_property_object::id_type()).time;
});
}
void staked_balance_object::finish_unstaking_tokens(share_type amount, chainbase::database& db) const {
db.modify(*this, [&amount](staked_balance_object& sbo) {
sbo.unstaking_balance -= amount;
});
db.modify( db.get<dynamic_global_property_object>(), [&]( auto& dgpo ){
dgpo.total_staked_tokens -= amount;
});
}
void staked_balance_object::propagate_votes(share_type staked_delta, chainbase::database& db) const {
if (producer_votes.contains<producer_slate>())
// This account votes for producers directly; update their stakes
boost::for_each(producer_votes.get<producer_slate>().range(), [&db, &staked_delta](const account_name& name) {
db.modify(db.get<producer_votes_object, by_owner_name>(name), [&db, &staked_delta](producer_votes_object& pvo) {
pvo.update_votes(staked_delta);
});
});
else {
}
}
} } } // namespace eosio::chain::contracts
......@@ -13,8 +13,8 @@ fc::variant_object get_config()
{
fc::mutable_variant_object result;
result["block_interval_ms"] = config::block_interval_ms;
result["producer_count"] = config::producer_count;
// result["block_interval_ms"] = config::block_interval_ms;
// result["producer_count"] = config::producer_count;
/// TODO: add extra config parms
return result;
}
......
......@@ -19,6 +19,10 @@ namespace eosio { namespace chain {
account_name name;
uint8_t vm_type = 0;
uint8_t vm_version = 0;
bool privileged = false;
bool frozen = false;
time_point_sec last_code_update;
digest_type code_version;
block_timestamp_type creation_date;
......
......@@ -19,11 +19,11 @@ class chain_controller;
class apply_context {
public:
apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta)
apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta, uint32_t checktime_limit)
:controller(con), db(db), act(a), mutable_controller(con),
mutable_db(db), used_authorizations(act.authorization.size(), false),
trx_meta(trx_meta) {}
trx_meta(trx_meta), _checktime_limit(checktime_limit) {}
void exec();
......@@ -96,10 +96,13 @@ class apply_context {
vector<account_name> get_active_producers() const;
const bytes& get_packed_transaction();
const chain_controller& controller;
const chainbase::database& db; ///< database where state is stored
const action& act; ///< message being applied
account_name receiver; ///< the code that is currently running
bool privileged = false;
chain_controller& mutable_controller;
chainbase::database& mutable_db;
......@@ -178,6 +181,9 @@ class apply_context {
console_append(fc::format_string(fmt, vo));
}
void checktime_start();
void checktime() const;
private:
void append_results(apply_results &&other) {
......@@ -194,6 +200,9 @@ class apply_context {
vector<shard_lock> _read_locks;
vector<scope_name> _write_scopes;
bytes _cached_trx;
fc::time_point _checktime_start;
const uint32_t _checktime_limit;
};
using apply_handler = std::function<void(apply_context&)>;
......@@ -245,7 +254,7 @@ using apply_handler = std::function<void(apply_context&)>;
template<typename ObjectType>
static auto& get(ObjectType& o) {
return o.primary_key;
return o.secondary_key;
}
};
......@@ -258,7 +267,7 @@ using apply_handler = std::function<void(apply_context&)>;
template<typename ObjectType>
static auto& get( ObjectType& o) {
return o.primary_key;
return o.tertiary_key;
}
};
......@@ -655,4 +664,4 @@ using apply_handler = std::function<void(apply_context&)>;
} } // namespace eosio::chain
FC_REFLECT(eosio::chain::apply_context::apply_results, (applied_actions)(generated_transactions));
FC_REFLECT(eosio::chain::apply_context::apply_results, (applied_actions)(generated_transactions))
......@@ -5,58 +5,68 @@
#pragma once
#include <fc/exception/exception.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/symbol.hpp>
/// eos with 8 digits of precision
#define EOS_SYMBOL (int64_t(4) | (uint64_t('E') << 8) | (uint64_t('O') << 16) | (uint64_t('S') << 24))
#define EOS_SYMBOL_VALUE (int64_t(4) | (uint64_t('E') << 8) | (uint64_t('O') << 16) | (uint64_t('S') << 24))
static const eosio::chain::symbol EOS_SYMBOL(EOS_SYMBOL_VALUE);
/// Defined to be largest power of 10 that fits in 53 bits of precision
#define EOS_MAX_SHARE_SUPPLY int64_t(1'000'000'000'000'000ll)
namespace eosio { namespace chain {
using asset_symbol = uint64_t;
/**
asset includes amount and currency symbol
asset::from_string takes a string of the form "10.0000 CUR" and constructs an asset
with amount = 10 and symbol(4,"CUR")
*/
struct asset
{
asset(share_type a = 0, asset_symbol id = EOS_SYMBOL)
:amount(a),symbol(id){}
explicit asset(share_type a = 0, symbol id = EOS_SYMBOL)
:amount(a), sym(id){}
share_type amount;
asset_symbol symbol;
share_type amount;
symbol sym;
double to_real()const { return static_cast<double>(amount) / precision(); }
uint8_t decimals()const;
string symbol_name()const;
int64_t precision()const;
void set_decimals(uint8_t d);
const symbol& get_symbol() const { return sym; }
static asset from_string(const string& from);
string to_string()const;
asset& operator += (const asset& o)
{
FC_ASSERT(symbol == o.symbol);
FC_ASSERT(get_symbol() == o.get_symbol());
amount += o.amount;
return *this;
}
asset& operator -= (const asset& o)
{
FC_ASSERT(symbol == o.symbol);
FC_ASSERT(get_symbol() == o.get_symbol());
amount -= o.amount;
return *this;
}
asset operator -()const { return asset(-amount, symbol); }
asset operator -()const { return asset(-amount, get_symbol()); }
friend bool operator == (const asset& a, const asset& b)
{
return std::tie(a.symbol, a.amount) == std::tie(b.symbol, b.amount);
return std::tie(a.get_symbol(), a.amount) == std::tie(b.get_symbol(), b.amount);
}
friend bool operator < (const asset& a, const asset& b)
{
FC_ASSERT(a.symbol == b.symbol);
return std::tie(a.amount,a.symbol) < std::tie(b.amount,b.symbol);
FC_ASSERT(a.get_symbol() == b.get_symbol());
return std::tie(a.amount,a.get_symbol()) < std::tie(b.amount,b.get_symbol());
}
friend bool operator <= (const asset& a, const asset& b) { return (a == b) || (a < b); }
friend bool operator != (const asset& a, const asset& b) { return !(a == b); }
......@@ -64,51 +74,21 @@ struct asset
friend bool operator >= (const asset& a, const asset& b) { return !(a < b); }
friend asset operator - (const asset& a, const asset& b) {
FC_ASSERT(a.symbol == b.symbol);
return asset(a.amount - b.amount, a.symbol);
FC_ASSERT(a.get_symbol() == b.get_symbol());
return asset(a.amount - b.amount, a.get_symbol());
}
friend asset operator + (const asset& a, const asset& b) {
FC_ASSERT(a.symbol == b.symbol);
return asset(a.amount + b.amount, a.symbol);
FC_ASSERT(a.get_symbol() == b.get_symbol());
return asset(a.amount + b.amount, a.get_symbol());
}
friend std::ostream& operator << (std::ostream& out, const asset& a) { return out << a.to_string(); }
};
struct price
{
asset base;
asset quote;
price(const asset& base = asset(), const asset quote = asset())
:base(base),quote(quote){}
static price max(asset_symbol base, asset_symbol quote);
static price min(asset_symbol base, asset_symbol quote);
price max()const { return price::max(base.symbol, quote.symbol); }
price min()const { return price::min(base.symbol, quote.symbol); }
double to_real()const { return base.to_real() / quote.to_real(); }
bool is_null()const;
void validate()const;
};
price operator / (const asset& base, const asset& quote);
inline price operator~(const price& p) { return price{p.quote,p.base}; }
bool operator < (const asset& a, const asset& b);
bool operator <= (const asset& a, const asset& b);
bool operator < (const price& a, const price& b);
bool operator <= (const price& a, const price& b);
bool operator > (const price& a, const price& b);
bool operator >= (const price& a, const price& b);
bool operator == (const price& a, const price& b);
bool operator != (const price& a, const price& b);
asset operator * (const asset& a, const price& b);
}} // namespace eosio::chain
......@@ -119,5 +99,4 @@ inline void from_variant(const fc::variant& var, eosio::chain::asset& vo) {
}
}
FC_REFLECT(eosio::chain::asset, (amount)(symbol))
FC_REFLECT(eosio::chain::price, (base)(quote))
FC_REFLECT(eosio::chain::asset, (amount)(sym))
......@@ -113,7 +113,7 @@ namespace eosio { namespace chain {
*/
struct signed_block : public signed_block_summary {
digest_type calculate_transaction_merkle_root()const;
vector<signed_transaction> input_transactions; /// this is loaded and indexed into map<id,trx> that is referenced by summary
vector<packed_transaction> input_transactions; /// this is loaded and indexed into map<id,trx> that is referenced by summary
};
struct shard_trace {
......
......@@ -50,7 +50,7 @@ namespace eosio { namespace chain {
skip_output_check = 1 << 13, ///< used to skip checks for outputs in block exactly matching those created from apply
pushed_transaction = 1 << 14, ///< used to indicate that the origination of the call was from a push_transaction, to determine time allotment
created_block = 1 << 15, ///< used to indicate that the origination of the call was for creating a block, to determine time allotment
received_block = 1 << 16, ///< used to indicate that the origination of the call was for a received block, to determine time allotment
received_block = 1 << 16, ///< used to indicate that the origination of the call was for a received block, to determine time allotment
genesis_setup = 1 << 17, ///< used to indicate that the origination of the call was for a genesis transaction
skip_missed_block_penalty = 1 << 18, ///< used to indicate that missed blocks shouldn't count against producers (used in long unit tests)
};
......@@ -76,7 +76,7 @@ namespace eosio { namespace chain {
void push_block( const signed_block& b, uint32_t skip = skip_nothing );
transaction_trace push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
transaction_trace push_transaction( const packed_transaction& trx, uint32_t skip = skip_nothing );
void push_deferred_transactions( bool flush = false );
......@@ -104,7 +104,7 @@ namespace eosio { namespace chain {
* This signal is emitted any time a new transaction is added to the pending
* block state.
*/
signal<void(const signed_transaction&)> on_pending_transaction;
signal<void(const packed_transaction&)> on_pending_transaction;
......@@ -121,6 +121,8 @@ namespace eosio { namespace chain {
* @return True if the controller is now applying a block; false otherwise
*/
bool is_applying_block()const { return _currently_applying_block; }
bool is_start_of_round( block_num_type n )const;
uint32_t blocks_per_round()const;
chain_id_type get_chain_id()const { return chain_id_type(); } /// TODO: make this hash of constitution
......@@ -164,7 +166,7 @@ namespace eosio { namespace chain {
* @return Subset of candidate_keys whose private keys should be used to sign transaction
* @throws fc::exception if candidate_keys does not contain all required keys
*/
flat_set<public_key_type> get_required_keys(const signed_transaction& trx, const flat_set<public_key_type>& candidate_keys)const;
flat_set<public_key_type> get_required_keys(const transaction& trx, const flat_set<public_key_type>& candidate_keys)const;
bool _push_block( const signed_block& b );
......@@ -199,19 +201,19 @@ namespace eosio { namespace chain {
template<typename Function>
auto without_pending_transactions( Function&& f )
{
vector<signed_transaction> old_input;
vector<transaction_metadata> old_input;
if( _pending_block )
old_input = move(_pending_block->input_transactions);
old_input = move(_pending_transaction_metas);
clear_pending();
/** after applying f() push previously input transactions on top */
auto on_exit = fc::make_scoped_exit( [&](){
for( const auto& t : old_input ) {
for( auto& t : old_input ) {
try {
if (!is_known_transaction(t.id()))
push_transaction( t );
if (!is_known_transaction(t.id))
_push_transaction( std::move(t) );
} catch ( ... ){}
}
});
......@@ -292,10 +294,17 @@ namespace eosio { namespace chain {
)const;
void set_txn_execution_times(uint32_t create_block_txn_execution_time, uint32_t rcvd_block_txn_execution_time, uint32_t txn_execution_time);
static const uint32_t default_received_block_transaction_execution_time_ms;
static const uint32_t default_transaction_execution_time_ms;
static const uint32_t default_create_block_transaction_execution_time_ms;
private:
const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const;
uint32_t txn_execution_time() const;
friend class contracts::chain_initializer;
friend class apply_context;
......@@ -310,8 +319,8 @@ namespace eosio { namespace chain {
//@}
transaction_trace _push_transaction( const signed_transaction& trx );
transaction_trace _push_transaction( transaction_metadata& data );
transaction_trace _push_transaction( const packed_transaction& trx );
transaction_trace _push_transaction( transaction_metadata&& data );
transaction_trace _apply_transaction( transaction_metadata& data );
transaction_trace __apply_transaction( transaction_metadata& data );
transaction_trace _apply_error( transaction_metadata& data );
......@@ -321,7 +330,7 @@ namespace eosio { namespace chain {
void _initialize_chain(contracts::chain_initializer& starter);
producer_schedule_type _calculate_producer_schedule()const;
const producer_schedule_type& _head_producer_schedule()const;
const shared_producer_schedule_type& _head_producer_schedule()const;
void replay();
......@@ -338,7 +347,8 @@ namespace eosio { namespace chain {
return f();
}
void check_transaction_authorization(const signed_transaction& trx,
void check_transaction_authorization(const transaction& trx,
const vector<signature_type>& signatures,
bool allow_unused_signatures = false)const;
......@@ -361,7 +371,7 @@ namespace eosio { namespace chain {
} FC_CAPTURE_AND_RETHROW( (trx) ) }
/// Validate transaction helpers @{
void validate_uniqueness(const signed_transaction& trx)const;
void validate_uniqueness(const transaction& trx)const;
void validate_tapos(const transaction& trx)const;
void validate_referenced_accounts(const transaction& trx)const;
void validate_expiration(const transaction& trx) const;
......@@ -418,7 +428,7 @@ namespace eosio { namespace chain {
optional<database::session> _pending_block_session;
optional<signed_block> _pending_block;
optional<block_trace> _pending_block_trace;
uint32_t _pending_transaction_count = 0;
vector<transaction_metadata> _pending_transaction_metas;
optional<cycle_trace> _pending_cycle_trace;
bool _currently_applying_block = false;
......@@ -431,6 +441,10 @@ namespace eosio { namespace chain {
map< account_name, map<handler_key, apply_handler> > _apply_handlers;
wasm_cache _wasm_cache;
uint32_t _create_block_txn_execution_time;
uint32_t _rcvd_block_txn_execution_time;
uint32_t _txn_execution_time;
};
} }
......@@ -13,12 +13,12 @@ typedef __uint128_t uint128_t;
const static auto default_block_log_dir = "block_log";
const static auto default_shared_memory_dir = "shared_mem";
const static auto default_shared_memory_size = 1024*1024*1024ll;
const static int producer_count = 21;
const static uint64_t system_account_name = N(eosio);
const static uint64_t nobody_account_name = N(nobody);
const static uint64_t anybody_account_name = N(anybody);
const static uint64_t producers_account_name = N(producers);
const static uint64_t eosio_system_account_name = N(eosio.system);
const static uint64_t eosio_auth_scope = N(eosio.auth);
const static uint64_t eosio_all_scope = N(eosio.all);
......@@ -71,13 +71,13 @@ const static uint16_t max_recursion_depth = 6;
/**
* The number of sequential blocks produced by a single producer
*/
const static int producer_repititions = 6;
const static int producer_repititions = 12;
/**
* The number of blocks produced per round is based upon all producers having a chance
* to produce all of their consecutive blocks.
*/
const static int blocks_per_round = producer_count * producer_repititions;
//const static int blocks_per_round = producer_count * producer_repititions;
const static int irreversible_threshold_percent= 70 * percent_1;
const static int max_producer_votes = 30;
......
......@@ -94,6 +94,7 @@ namespace impl {
template<typename T>
constexpr bool single_type_requires_abi_v() {
return std::is_base_of<transaction, T>::value ||
std::is_same<T, packed_transaction>::value ||
std::is_same<T, action>::value ||
std::is_same<T, transaction_trace>::value ||
std::is_same<T, action_trace>::value;
......@@ -135,6 +136,87 @@ namespace impl {
template<typename T>
using require_abi_t = std::enable_if_t<type_requires_abi_v<T>(), int>;
struct abi_to_variant {
/**
* template which overloads add for types which are not relvant to ABI information
* and can be degraded to the normal ::to_variant(...) processing
*/
template<typename M, typename Resolver, not_require_abi_t<M> = 1>
static void add( mutable_variant_object &mvo, const char* name, const M& v, Resolver )
{
mvo(name,v);
}
/**
* template which overloads add for types which contain ABI information in their trees
* for these types we create new ABI aware visitors
*/
template<typename M, typename Resolver, require_abi_t<M> = 1>
static void add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver );
/**
* template which overloads add for vectors of types which contain ABI information in their trees
* for these members we call ::add in order to trigger further processing
*/
template<typename M, typename Resolver, require_abi_t<M> = 1>
static void add( mutable_variant_object &mvo, const char* name, const vector<M>& v, Resolver resolver )
{
vector<variant> array;
array.reserve(v.size());
for (const auto& iter: v) {
mutable_variant_object elem_mvo;
add(elem_mvo, "_", iter, resolver);
array.emplace_back(std::move(elem_mvo["_"]));
}
mvo(name, std::move(array));
}
/**
* overload of to_variant_object for actions
* @tparam Resolver
* @param act
* @param resolver
* @return
*/
template<typename Resolver>
static void add(mutable_variant_object &out, const char* name, const action& act, Resolver resolver) {
mutable_variant_object mvo;
mvo("account", act.account);
mvo("name", act.name);
mvo("authorization", act.authorization);
auto abi = resolver(act.account);
if (abi.valid()) {
auto type = abi->get_action_type(act.name);
mvo("data", abi->binary_to_variant(type, act.data));
mvo("hex_data", act.data);
} else {
mvo("data", act.data);
}
out(name, std::move(mvo));
}
/**
* overload of to_variant_object for packed_transaction
* @tparam Resolver
* @param act
* @param resolver
* @return
*/
template<typename Resolver>
static void add(mutable_variant_object &out, const char* name, const packed_transaction& ptrx, Resolver resolver) {
mutable_variant_object mvo;
mvo("signatures", ptrx.signatures);
mvo("compression", ptrx.compression);
mvo("hex_data", ptrx.data);
transaction trx = ptrx.get_transaction();
add(mvo, "data", trx, resolver);
out(name, std::move(mvo));
}
};
/**
* Reflection visitor that uses a resolver to resolve ABIs for nested types
* this will degrade to the common fc::to_variant as soon as the type no longer contains
......@@ -162,77 +244,114 @@ namespace impl {
template<typename Member, class Class, Member (Class::*member) >
void operator()( const char* name )const
{
this->add(_vo,name,(_val.*member));
abi_to_variant::add(_vo, name, (_val.*member), _resolver);
}
private:
mutable_variant_object& _vo;
const T& _val;
Resolver _resolver;
};
/**
* template which overloads add for types which are not relvant to ABI information
* and can be degraded to the normal ::to_variant(...) processing
*/
template<typename M, not_require_abi_t<M> = 1>
void add( mutable_variant_object& vo, const char* name, const M& v )const
{
vo(name,v);
struct abi_from_variant {
/**
* template which overloads extract for types which are not relvant to ABI information
* and can be degraded to the normal ::from_variant(...) processing
*/
template<typename M, typename Resolver, not_require_abi_t<M> = 1>
static void extract( const variant& v, M& o, Resolver )
{
from_variant(v, o);
}
/**
* template which overloads extract for types which contain ABI information in their trees
* for these types we create new ABI aware visitors
*/
template<typename M, typename Resolver, require_abi_t<M> = 1>
static void extract( const variant& v, M& o, Resolver resolver );
/**
* template which overloads extract for vectors of types which contain ABI information in their trees
* for these members we call ::extract in order to trigger further processing
*/
template<typename M, typename Resolver, require_abi_t<M> = 1>
static void extract( const variant& v, vector<M>& o, Resolver resolver )
{
const variants& array = v.get_array();
o.clear();
o.reserve( array.size() );
for( auto itr = array.begin(); itr != array.end(); ++itr ) {
M o_iter;
extract(*itr, o_iter, resolver);
o.emplace_back(std::move(o_iter));
}
}
/**
* template which overloads add for types which contain ABI information in their trees
* for these types we create new ABI aware visitors
*/
template<typename M, require_abi_t<M> = 1>
void add( mutable_variant_object& vo, const char* name, const M& v )const
{
mutable_variant_object mvo;
fc::reflector<M>::visit( impl::abi_to_variant_visitor<M, decltype(_resolver)>( mvo, v, _resolver ) );
vo(name, std::move(mvo));
/**
* Non templated overload that has priority for the action structure
* this type has members which must be directly translated by the ABI so it is
* exploded and processed explicitly
*/
template<typename Resolver>
static void extract( const variant& v, action& act, Resolver resolver )
{
const variant_object& vo = v.get_object();
FC_ASSERT(vo.contains("account"));
FC_ASSERT(vo.contains("name"));
from_variant(vo["account"], act.account);
from_variant(vo["name"], act.name);
if (vo.contains("authorization")) {
from_variant(vo["authorization"], act.authorization);
}
/**
* template which overloads add for vectors of types which contain ABI information in their trees
* for these members we call ::add in order to trigger further processing
*/
template<typename M, require_abi_t<M> = 1>
void add( mutable_variant_object& vo, const char* name, const vector<M>& v )const
{
vector<variant> array(v.size());
for (const auto& iter: v) {
mutable_variant_object mvo;
add(mvo, "_", iter);
array.emplace_back(std::move(mvo["_"]));
if( vo.contains( "data" ) ) {
const auto& data = vo["data"];
if( data.is_string() ) {
from_variant(data, act.data);
} else if ( data.is_object() ) {
auto abi = resolver(act.account);
if (abi.valid()) {
auto type = abi->get_action_type(act.name);
act.data = std::move(abi->variant_to_binary(type, data));
}
}
vo(name, std::move(array));
}
/**
* Non templated overload that has priority for the action structure
* this type has members which must be directly translated by the ABI so it is
* exploded and processed explicitly
*/
void add( mutable_variant_object& vo, const char* name, const action& v )const
{
mutable_variant_object mvo;
mvo("account", v.account);
mvo("name", v.name);
mvo("authorization", v.authorization);
auto abi = _resolver(v.account);
if (abi.valid()) {
auto type = abi->get_action_type(v.name);
mvo("data", abi->binary_to_variant(type, v.data));
mvo("hex_data", v.data);
} else {
mvo("data", v.data);
if (act.data.empty()) {
if( vo.contains( "hex_data" ) ) {
const auto& data = vo["hex_data"];
if( data.is_string() ) {
from_variant(data, act.data);
}
}
vo(name, std::move( mvo ));
}
FC_ASSERT(!act.data.empty(), "Failed to deserialize data for ${account}:${name}", ("account", act.account)("name", act.name));
}
mutable_variant_object& _vo;
const T& _val;
Resolver _resolver;
template<typename Resolver>
static void extract( const variant& v, packed_transaction& ptrx, Resolver resolver ) {
const variant_object& vo = v.get_object();
FC_ASSERT(vo.contains("signatures"));
FC_ASSERT(vo.contains("compression"));
from_variant(vo["signatures"], ptrx.signatures);
from_variant(vo["compression"], ptrx.compression);
if (vo.contains("hex_data") && vo["hex_data"].is_string() && !vo["hex_data"].as_string().empty()) {
from_variant(vo["hex_data"], ptrx.data);
} else {
FC_ASSERT(vo.contains("data"));
if (vo["data"].is_string()) {
from_variant(vo["data"], ptrx.data);
} else {
transaction trx;
extract(vo["data"], trx, resolver);
ptrx.set_transaction(trx, ptrx.compression);
}
}
}
};
/**
......@@ -264,109 +383,40 @@ namespace impl {
{
auto itr = _vo.find(name);
if( itr != _vo.end() )
extract( itr->value(), _val.*member );
abi_from_variant::extract( itr->value(), _val.*member, _resolver );
}
private:
/**
* template which overloads extract for types which are not relvant to ABI information
* and can be degraded to the normal ::from_variant(...) processing
*/
template<typename M, not_require_abi_t<M> = 1>
void extract( const variant& v, M& o )const
{
from_variant(v, o);
}
/**
* template which overloads extract for types which contain ABI information in their trees
* for these types we create new ABI aware visitors
*/
template<typename M, require_abi_t<M> = 1>
void extract( const variant& v, M& o )const
{
const variant_object& vo = v.get_object();
fc::reflector<M>::visit( abi_from_variant_visitor<M, decltype(_resolver)>( vo, o, _resolver ) );
}
/**
* template which overloads extract for vectors of types which contain ABI information in their trees
* for these members we call ::extract in order to trigger further processing
*/
template<typename M, require_abi_t<M> = 1>
void extract( const variant& v, vector<M>& o )const
{
const variants& array = v.get_array();
o.clear();
o.reserve( array.size() );
for( auto itr = array.begin(); itr != array.end(); ++itr ) {
M o_iter;
extract(*itr, o_iter);
o.emplace_back(std::move(o_iter));
}
}
/**
* Non templated overload that has priority for the action structure
* this type has members which must be directly translated by the ABI so it is
* exploded and processed explicitly
*/
void extract( const variant& v, action& act )const
{
const variant_object& vo = v.get_object();
FC_ASSERT(vo.contains("account"));
FC_ASSERT(vo.contains("name"));
from_variant(vo["account"], act.account);
from_variant(vo["name"], act.name);
if (vo.contains("authorization")) {
from_variant(vo["authorization"], act.authorization);
}
if( vo.contains( "data" ) ) {
const auto& data = vo["data"];
if( data.is_string() ) {
from_variant(data, act.data);
} else if ( data.is_object() ) {
auto abi = _resolver(act.account);
if (abi.valid()) {
auto type = abi->get_action_type(act.name);
act.data = std::move(abi->variant_to_binary(type, data));
}
}
}
if (act.data.empty()) {
if( vo.contains( "hex_data" ) ) {
const auto& data = vo["hex_data"];
if( data.is_string() ) {
from_variant(data, act.data);
}
}
}
FC_ASSERT(!act.data.empty(), "Failed to deserialize data for ${account}:${name}", ("account", act.account)("name", act.name));
}
const variant_object& _vo;
T& _val;
Resolver _resolver;
};
template<typename M, typename Resolver, require_abi_t<M>>
void abi_to_variant::add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver ) {
mutable_variant_object member_mvo;
fc::reflector<M>::visit( impl::abi_to_variant_visitor<M, Resolver>( member_mvo, v, resolver ) );
mvo(name, std::move(member_mvo));
}
template<typename M, typename Resolver, require_abi_t<M>>
void abi_from_variant::extract( const variant& v, M& o, Resolver resolver ) {
const variant_object& vo = v.get_object();
fc::reflector<M>::visit( abi_from_variant_visitor<M, decltype(resolver)>( vo, o, resolver ) );
}
}
template<typename T, typename Resolver>
void abi_serializer::to_variant( const T& o, variant& vo, Resolver resolver ) try {
mutable_variant_object mvo;
fc::reflector<T>::visit( impl::abi_to_variant_visitor<T, Resolver>( mvo, o, resolver ) );
vo = std::move(mvo);
impl::abi_to_variant::add(mvo, "_", o, resolver);
vo = std::move(mvo["_"]);
} FC_RETHROW_EXCEPTIONS(error, "Failed to serialize type", ("object",o))
template<typename T, typename Resolver>
void abi_serializer::from_variant( const variant& v, T& o, Resolver resolver ) try {
const variant_object& vo = v.get_object();
fc::reflector<T>::visit( impl::abi_from_variant_visitor<T, Resolver>( vo, o, resolver ) );
impl::abi_from_variant::extract(v, o, resolver);
} FC_RETHROW_EXCEPTIONS(error, "Failed to deserialize variant", ("variant",v))
......
......@@ -172,6 +172,44 @@ namespace eosio { namespace chain { namespace contracts {
>
>;
struct key64x64_value_object : public chainbase::object<key64x64_value_object_type, key64x64_value_object> {
OBJECT_CTOR(key64x64_value_object, (value))
typedef uint64_t key_type;
static const int number_of_keys = 2;
id_type id;
table_id t_id;
uint64_t primary_key;
uint64_t secondary_key;
shared_string value;
};
using key64x64_value_index = chainbase::shared_multi_index_container<
key64x64_value_object,
indexed_by<
ordered_unique<tag<by_id>, member<key64x64_value_object, key64x64_value_object::id_type, &key64x64_value_object::id>>,
ordered_unique<tag<by_scope_primary>,
composite_key< key64x64_value_object,
member<key64x64_value_object, table_id, &key64x64_value_object::t_id>,
member<key64x64_value_object, uint64_t, &key64x64_value_object::primary_key>,
member<key64x64_value_object, uint64_t, &key64x64_value_object::secondary_key>
>,
composite_key_compare< std::less<table_id>,std::less<uint64_t>,std::less<uint64_t> >
>,
ordered_unique<tag<by_scope_secondary>,
composite_key< key64x64_value_object,
member<key64x64_value_object, table_id, &key64x64_value_object::t_id>,
member<key64x64_value_object, uint64_t, &key64x64_value_object::secondary_key>,
member<key64x64_value_object, typename key64x64_value_object::id_type, &key64x64_value_object::id>
>,
composite_key_compare< std::less<table_id>,std::less<uint64_t>,std::less<typename key64x64_value_object::id_type> >
>
>
>;
struct key64x64x64_value_object : public chainbase::object<key64x64x64_value_object_type, key64x64x64_value_object> {
OBJECT_CTOR(key64x64x64_value_object, (value))
......@@ -227,10 +265,12 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::table_id_object, eosio::chain:
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key_value_object, eosio::chain::contracts::key_value_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::keystr_value_object, eosio::chain::contracts::keystr_value_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key128x128_value_object, eosio::chain::contracts::key128x128_value_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64_value_object, eosio::chain::contracts::key64x64_value_index)
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::key64x64x64_value_object, eosio::chain::contracts::key64x64x64_value_index)
FC_REFLECT(eosio::chain::contracts::table_id_object, (id)(code)(scope)(table) )
FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(bta)(value) )
FC_REFLECT(eosio::chain::contracts::keystr_value_object, (id)(t_id)(primary_key)(bta)(value) )
FC_REFLECT(eosio::chain::contracts::key128x128_value_object, (id)(t_id)(primary_key)(secondary_key)(bta)(value) )
FC_REFLECT(eosio::chain::contracts::key64x64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(tertiary_key)(bta)(value) )
FC_REFLECT(eosio::chain::contracts::key_value_object, (id)(t_id)(primary_key)(value) )
FC_REFLECT(eosio::chain::contracts::keystr_value_object, (id)(t_id)(primary_key)(value) )
FC_REFLECT(eosio::chain::contracts::key128x128_value_object, (id)(t_id)(primary_key)(secondary_key)(value) )
FC_REFLECT(eosio::chain::contracts::key64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(value) )
FC_REFLECT(eosio::chain::contracts::key64x64x64_value_object, (id)(t_id)(primary_key)(secondary_key)(tertiary_key)(value) )
......@@ -25,23 +25,10 @@ namespace eosio { namespace chain { namespace contracts {
void apply_eosio_passrecovery(apply_context&);
void apply_eosio_vetorecovery(apply_context&);
void apply_eosio_transfer(apply_context& context);
void apply_eosio_lock(apply_context& context);
void apply_eosio_claim(apply_context&);
void apply_eosio_unlock(apply_context&);
void apply_eosio_okproducer(apply_context&);
void apply_eosio_setproducer(apply_context&);
void apply_eosio_setproxy(apply_context&);
void apply_eosio_setcode(apply_context&);
void apply_eosio_setabi(apply_context&);
void apply_eosio_nonce(apply_context&);
void apply_eosio_onerror(apply_context&);
///@} end action handlers
share_type get_eosio_balance( const chainbase::database& db, const account_name& account );
} } } /// namespace eosio::contracts
......@@ -61,6 +61,9 @@ struct genesis_state_type {
};
time_point initial_timestamp;
public_key_type initial_key;
public_key_type eosio_system_key;
vector<initial_account_type> initial_accounts;
vector<initial_producer_type> initial_producers;
......@@ -85,5 +88,5 @@ FC_REFLECT(eosio::chain::contracts::genesis_state_type::initial_account_type,
FC_REFLECT(eosio::chain::contracts::genesis_state_type::initial_producer_type, (owner_name)(block_signing_key))
FC_REFLECT(eosio::chain::contracts::genesis_state_type,
(initial_timestamp)(initial_configuration)(initial_accounts)
(initial_timestamp)(initial_key)(initial_configuration)(initial_accounts)
(initial_producers)(initial_chain_id))
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
/// @file This file #include's all database objects/indices used by the C++ native contract implementation
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/multi_index_includes.hpp>
#include <eosio/utilities/exception_macros.hpp>
#include <chainbase/chainbase.hpp>
#include <boost/multi_index/mem_fun.hpp>
namespace eosio { namespace chain { namespace contracts {
FC_DECLARE_EXCEPTION(producer_race_overflow_exception, 10000000, "Producer Virtual Race time has overflowed");
/**
* @brief The producer_votes_object class tracks all votes for and by the block producers
*
* This class tracks the voting for block producers, as well as the virtual time 'race' to select the runner-up block
* producer.
*
* This class also tracks the votes cast by block producers on various chain configuration options and key documents.
*/
class producer_votes_object : public chainbase::object<producer_votes_object_type, producer_votes_object> {
OBJECT_CTOR(producer_votes_object)
id_type id;
account_name owner_name;
share_type votes = 0;
/**
* @brief Update the tally of votes for the producer
* @param delta_votes The change in votes since the last update
*/
void update_votes(share_type delta_votes) {
votes += delta_votes;
}
};
using boost::multi_index::const_mem_fun;
/// Index producers by their owner's name
struct by_owner_name;
/// Index producers by projected race finishing time, from soonest to latest
struct by_projected_race_finish_time;
/// Index producers by votes, from greatest to least
struct by_votes;
using producer_votes_multi_index = chainbase::shared_multi_index_container<
producer_votes_object,
indexed_by<
ordered_unique< tag<by_id>,
member<producer_votes_object, producer_votes_object::id_type, &producer_votes_object::id>
>,
ordered_unique< tag<by_owner_name>,
member<producer_votes_object, account_name, &producer_votes_object::owner_name>
>,
ordered_unique< tag<by_votes>,
composite_key<producer_votes_object,
member<producer_votes_object, share_type, &producer_votes_object::votes>,
member<producer_votes_object, producer_votes_object::id_type, &producer_votes_object::id>
>,
composite_key_compare< std::greater<share_type>,std::less<producer_votes_object::id_type> >
>
>
>;
/// Index proxies by the proxy target account name
struct by_target_name;
} } } // namespace eosio::chain::contracts
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::producer_votes_object, eosio::chain::contracts::producer_votes_multi_index)
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosio/chain/types.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/multi_index_includes.hpp>
#include <chainbase/chainbase.hpp>
#include <fc/static_variant.hpp>
namespace eosio { namespace chain { namespace contracts {
/**
* @brief The producer_slate struct stores a list of producers voted on by an account
*/
struct producer_slate {
std::array<account_name, config::max_producer_votes> votes;
size_t size = 0;
void add(account_name producer) {
votes[size++] = producer;
std::inplace_merge(votes.begin(), votes.begin() + size - 1, votes.begin() + size);
}
void remove(account_name producer) {
auto itr = std::remove(votes.begin(), votes.begin() + size, producer);
size = std::distance(votes.begin(), itr);
}
bool contains(account_name producer) const {
return std::binary_search(votes.begin(), votes.begin() + size, producer);
}
auto range() { return boost::make_iterator_range_n(votes.begin(), size); }
auto range() const { return boost::make_iterator_range_n(votes.begin(), size); }
};
/**
* @brief The staked_balance_object class tracks the staked balance (voting balance) for accounts
*/
class staked_balance_object : public chainbase::object<staked_balance_object_type, staked_balance_object> {
OBJECT_CTOR(staked_balance_object)
id_type id;
account_name owner_name;
share_type staked_balance = 0;
share_type unstaking_balance = 0;
time_point last_unstaking_time = time_point::maximum();
uint128_t staked_balance_percent = 0;
/// The account's vote on producers. This may either be a list of approved producers, or an account to proxy vote to
fc::static_variant<producer_slate, account_name> producer_votes = producer_slate{};
/**
* @brief Add the provided stake to this balance, maintaining invariants
* @param new_stake The new stake to add to the balance
* @param db Read-write reference to the database
*
* This method will update this object with the new stake, while maintaining invariants around the stake balance,
* such as by updating vote tallies
*/
void stake_tokens(share_type new_stake, chainbase::database& db) const;
/**
* @brief Begin unstaking the specified amount of stake, maintaining invariants
* @param amount The amount of stake to begin unstaking
* @param db Read-write reference to the database
*
* This method will update this object's balances while maintaining invariants around the stake balances, such as by
* updating vote tallies
*/
void begin_unstaking_tokens(share_type amount, chainbase::database& db) const;
/**
* @brief Finish unstaking the specified amount of stake
* @param amount The amount of stake to finish unstaking
* @param db Read-write reference to the database
*
* This method will update this object's balances. There aren't really any invariants to maintain on this call, as
* the tokens are already unstaked and removed from vote tallies, but it is provided for completeness' sake.
*/
void finish_unstaking_tokens(share_type amount, chainbase::database& db) const;
/**
* @brief Propagate the specified change in stake to the producer votes or the proxy
* @param staked_delta The change in stake
* @param db Read-write reference to the database
*
* This method will apply the provided delta in voting stake to the next stage in the producer voting pipeline,
* whether that be the producers in the slate, or the account the votes are proxied to.
*
* This method will *not* update this object in any way. It will not adjust @ref staked_balance, etc
*/
void propagate_votes(share_type staked_delta, chainbase::database& db) const;
};
struct by_owner_name;
using staked_balance_multi_index = chainbase::shared_multi_index_container<
staked_balance_object,
indexed_by<
ordered_unique<tag<by_id>,
member<staked_balance_object, staked_balance_object::id_type, &staked_balance_object::id>
>,
ordered_unique<tag<by_owner_name>,
member<staked_balance_object, account_name, &staked_balance_object::owner_name>
>
>
>;
} } } // namespace eosio::chain::contracts
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::staked_balance_object, eosio::chain::contracts::staked_balance_multi_index)
......@@ -118,60 +118,6 @@ struct transfer {
}
};
struct lock {
lock() = default;
lock(const account_name& from, const account_name& to, const share_type& amount)
:from(from), to(to), amount(amount)
{}
account_name from;
account_name to;
share_type amount;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(lock);
}
};
struct unlock {
unlock() = default;
unlock(const account_name& account, const share_type& amount)
:account(account), amount(amount)
{}
account_name account;
share_type amount;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(unlock);
}
};
struct claim {
claim() = default;
claim(const account_name& account, const share_type& amount)
:account(account), amount(amount)
{}
account_name account;
share_type amount;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(claim);
}
};
struct newaccount {
account_name creator;
......@@ -179,7 +125,6 @@ struct newaccount {
authority owner;
authority active;
authority recovery;
asset deposit;
static account_name get_account() {
return config::system_account_name;
......@@ -218,61 +163,6 @@ struct setabi {
}
};
struct setproducer {
setproducer() = default;
setproducer(const account_name& name, const public_key_type& key, const chain_config& configuration)
:name(name), key(key), configuration(configuration)
{}
account_name name;
public_key_type key;
chain_config configuration;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(setproducer);
}
};
struct okproducer {
okproducer() = default;
okproducer(const account_name& voter, const account_name& producer, const int8_t& approve)
:voter(voter), producer(producer), approve(approve)
{}
account_name voter;
account_name producer;
int8_t approve;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(okproducer);
}
};
struct setproxy {
setproxy() = default;
setproxy(const account_name& stakeholder, const account_name& proxy)
:stakeholder(stakeholder), proxy(proxy)
{}
account_name stakeholder;
account_name proxy;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(setproxy);
}
};
struct updateauth {
account_name account;
......@@ -397,18 +287,6 @@ struct vetorecovery {
}
};
using nonce_type = name;
struct nonce {
nonce_type value;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(nonce);
}
};
} } } /// namespace eosio::chain::contracts
......@@ -418,16 +296,10 @@ FC_REFLECT( eosio::chain::contracts::struct_def , (name)(b
FC_REFLECT( eosio::chain::contracts::action_def , (name)(type) )
FC_REFLECT( eosio::chain::contracts::table_def , (name)(index_type)(key_names)(key_types)(type) )
FC_REFLECT( eosio::chain::contracts::abi_def , (types)(structs)(actions)(tables) )
FC_REFLECT( eosio::chain::contracts::transfer , (from)(to)(amount)(memo) )
FC_REFLECT( eosio::chain::contracts::lock , (from)(to)(amount) )
FC_REFLECT( eosio::chain::contracts::unlock , (account)(amount) )
FC_REFLECT( eosio::chain::contracts::claim , (account)(amount) )
FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery)(deposit) )
FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery) )
FC_REFLECT( eosio::chain::contracts::setcode , (account)(vmtype)(vmversion)(code) ) //abi
FC_REFLECT( eosio::chain::contracts::setabi , (account)(abi) )
FC_REFLECT( eosio::chain::contracts::setproducer , (name)(key)(configuration) )
FC_REFLECT( eosio::chain::contracts::okproducer , (voter)(producer)(approve) )
FC_REFLECT( eosio::chain::contracts::setproxy , (stakeholder)(proxy) )
FC_REFLECT( eosio::chain::contracts::updateauth , (account)(permission)(parent)(data) )
FC_REFLECT( eosio::chain::contracts::deleteauth , (account)(permission) )
FC_REFLECT( eosio::chain::contracts::linkauth , (account)(code)(type)(requirement) )
......@@ -435,5 +307,4 @@ FC_REFLECT( eosio::chain::contracts::unlinkauth , (account
FC_REFLECT( eosio::chain::contracts::postrecovery , (account)(data)(memo) )
FC_REFLECT( eosio::chain::contracts::passrecovery , (account) )
FC_REFLECT( eosio::chain::contracts::vetorecovery , (account) )
FC_REFLECT( eosio::chain::contracts::nonce , (value) )
......@@ -20,6 +20,7 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( unlinkable_block_exception, eosio::chain::chain_exception, 3090000, "unlinkable block" )
FC_DECLARE_DERIVED_EXCEPTION( black_swan_exception, eosio::chain::chain_exception, 3100000, "black swan" )
FC_DECLARE_DERIVED_EXCEPTION( unknown_block_exception, eosio::chain::chain_exception, 3110000, "unknown block" )
FC_DECLARE_DERIVED_EXCEPTION( chain_type_exception, eosio::chain::chain_exception, 3120000, "chain type exception" )
FC_DECLARE_DERIVED_EXCEPTION( block_tx_output_exception, eosio::chain::block_validate_exception, 3020001, "transaction outputs in block do not match transaction outputs from applying block" )
FC_DECLARE_DERIVED_EXCEPTION( block_concurrency_exception, eosio::chain::block_validate_exception, 3020002, "block does not guarantee concurrent exection without conflicts" )
......@@ -44,6 +45,7 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( tx_msgs_auth_exceeded, eosio::chain::transaction_exception, 3030018, "Number of transaction messages per authorized account has been exceeded" )
FC_DECLARE_DERIVED_EXCEPTION( tx_msgs_code_exceeded, eosio::chain::transaction_exception, 3030019, "Number of transaction messages per code account has been exceeded" )
FC_DECLARE_DERIVED_EXCEPTION( wasm_execution_error, eosio::chain::transaction_exception, 3030020, "Runtime Error Processing WASM" )
FC_DECLARE_DERIVED_EXCEPTION( tx_decompression_error, eosio::chain::transaction_exception, 3030020, "Error decompressing transaction" )
FC_DECLARE_DERIVED_EXCEPTION( account_name_exists_exception, eosio::chain::action_validate_exception, 3040001, "account name already exists" )
FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, eosio::chain::utility_exception, 3060001, "invalid pts address" )
......@@ -51,6 +53,13 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( pop_empty_chain, eosio::chain::undo_database_exception, 3070001, "there are no blocks to pop" )
FC_DECLARE_DERIVED_EXCEPTION( name_type_exception, eosio::chain::chain_type_exception, 3120001, "Invalid name" )
FC_DECLARE_DERIVED_EXCEPTION( public_key_type_exception, eosio::chain::chain_type_exception, 3120002, "Invalid public key" )
FC_DECLARE_DERIVED_EXCEPTION( authority_type_exception, eosio::chain::chain_type_exception, 3120003, "Invalid authority" )
FC_DECLARE_DERIVED_EXCEPTION( action_type_exception, eosio::chain::chain_type_exception, 3120004, "Invalid action" )
FC_DECLARE_DERIVED_EXCEPTION( transaction_type_exception, eosio::chain::chain_type_exception, 3120005, "Invalid transaction" )
FC_DECLARE_DERIVED_EXCEPTION( abi_type_exception, eosio::chain::chain_type_exception, 3120006, "Invalid ABI" )
#define EOS_RECODE_EXC( cause_type, effect_type ) \
catch( const cause_type& e ) \
......
......@@ -18,6 +18,14 @@
namespace eosio { namespace chain {
struct blocknum_producer_schedule {
blocknum_producer_schedule( allocator<char> a )
:second(a){}
block_num_type first;
shared_producer_schedule_type second;
};
/**
* @class global_property_object
* @brief Maintains global state information (committee_member list, current fees)
......@@ -28,18 +36,19 @@ namespace eosio { namespace chain {
*/
class global_property_object : public chainbase::object<global_property_object_type, global_property_object>
{
OBJECT_CTOR(global_property_object, (pending_active_producers) )
OBJECT_CTOR(global_property_object, (active_producers)(new_active_producers)(pending_active_producers) )
id_type id;
chain_config configuration;
producer_schedule_type active_producers;
shared_producer_schedule_type active_producers;
shared_producer_schedule_type new_active_producers;
/** every block that has change in producer schedule gets inserted into this list, this includes
* all blocks that see a change in producer signing keys or vote order.
*
* TODO: consider moving this to a more effeicent datatype
*/
shared_vector< pair<block_num_type, producer_schedule_type> > pending_active_producers;
shared_vector< blocknum_producer_schedule > pending_active_producers;
};
......@@ -63,7 +72,10 @@ namespace eosio { namespace chain {
time_point time;
account_name current_producer;
share_type total_staked_tokens;
uint64_t total_net_weight = 1;
uint64_t total_cpu_weight = 1;
uint64_t total_db_capacity = 1024*1024*1024ull*1024ull;
uint64_t total_db_reserved = 0;
/**
* The current absolute slot number. Equal to the total
......
#pragma once
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>
#include <chainbase/chainbase.hpp>
namespace eosio { namespace chain {
......@@ -23,7 +24,31 @@ namespace eosio { namespace chain {
*/
struct producer_schedule_type {
uint32_t version = 0; ///< sequentially incrementing version number
fc::array<producer_key,config::producer_count> producers;
vector<producer_key> producers;
};
struct shared_producer_schedule_type {
shared_producer_schedule_type( chainbase::allocator<char> alloc )
:producers(alloc){}
shared_producer_schedule_type& operator=( const producer_schedule_type& a ) {
version = a.version;
producers.reserve( a.producers.size() );
for( const auto& p : a.producers )
producers.push_back(p);
return *this;
}
operator producer_schedule_type()const {
producer_schedule_type result;
result.producers.reserve(producers.size());
for( const auto& p : producers )
result.producers.push_back(p);
return result;
}
uint32_t version = 0; ///< sequentially incrementing version number
shared_vector<producer_key> producers;
};
......
......@@ -55,6 +55,10 @@ namespace eosio { namespace chain {
id_type id;
account_name owner;
uint64_t net_weight = 0;
uint64_t cpu_weight = 0;
uint64_t db_reserved_capacity = 0; /// bytes
average_accumulator<config::bandwidth_average_window_ms> bytes;
average_accumulator<config::compute_average_window_ms> acts; ///< tracks a logical number of actions processed
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <fc/exception/exception.hpp>
#include <eosio/chain/types.hpp>
#include <string>
#include <functional>
namespace eosio {
namespace chain {
/**
class symbol represents a token and contains precision and name.
When encoded as a uint64_t, first byte represents the number of decimals, remaining bytes
represent token name.
Name must only include upper case alphabets.
from_string constructs a symbol from an input a string of the form "4,EOS"
where the integer represents number of decimals. Number of decimals must be larger than zero.
*/
static constexpr uint64_t string_to_symbol_c(uint8_t precision, const char* str) {
uint32_t len = 0;
while (str[len]) ++len;
uint64_t result = 0;
// No validation is done at compile time
for (uint32_t i = 0; i < len; ++i) {
result |= (uint64_t(str[i]) << (8*(1+i)));
}
result |= uint64_t(precision);
return result;
}
#define SY(P,X) ::eosio::chain::string_to_symbol_c(P,#X)
static uint64_t string_to_symbol(uint8_t precision, const char* str) {
try {
uint32_t len = 0;
while(str[len]) ++len;
uint64_t result = 0;
for (uint32_t i = 0; i < len; ++i) {
// All characters must be upper case alaphabets
FC_ASSERT (str[i] >= 'A' && str[i] <= 'Z', "invalid character in symbol name");
result |= (uint64_t(str[i]) << (8*(i+1)));
}
result |= uint64_t(precision);
return result;
} FC_CAPTURE_LOG_AND_RETHROW((str))
}
class symbol {
public:
explicit symbol(uint8_t p, const char* s): m_value(string_to_symbol(p, s)) { }
explicit symbol(uint64_t v = SY(4, EOS)): m_value(v) { }
static symbol from_string(const string& from)
{
try {
string s = fc::trim(from);
FC_ASSERT(!s.empty(), "creating symbol from empty string");
auto comma_pos = s.find(',');
FC_ASSERT(comma_pos != string::npos, "missing comma in symbol");
auto prec_part = s.substr(0, comma_pos);
uint8_t p = fc::to_int64(prec_part);
FC_ASSERT(p > 0, "zero decimals in symbol");
string name_part = s.substr(comma_pos + 1);
return symbol(string_to_symbol(p, name_part.c_str()));
} FC_CAPTURE_LOG_AND_RETHROW((from))
}
uint64_t value() const { return m_value; }
bool valid() const
{
if (decimals() == 0) return false;
const auto& s = name();
return valid_name(s);
}
static bool valid_name(const string& name)
{
return all_of(name.begin(), name.end(), [](char c)->bool { return (c >= 'A' && c <= 'Z'); });
}
uint8_t decimals() const { return m_value & 0xFF; }
uint64_t precision() const
{
static int64_t table[] = {
1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000ll,
1000000000ll, 10000000000ll,
100000000000ll, 1000000000000ll,
10000000000000ll, 100000000000000ll
};
return table[ decimals() ];
}
string name() const
{
uint64_t v = m_value;
v >>= 8;
string result;
while (v > 0) {
char c = v & 0xFF;
result += c;
v >>= 8;
}
return result;
}
explicit operator string() const
{
uint64_t v = m_value;
uint8_t p = v & 0xFF;
string ret = eosio::chain::to_string(p);
ret += ',';
ret += name();
return ret;
}
string to_string() const { return string(*this); }
template <typename DataStream>
friend DataStream& operator<< (DataStream& ds, const symbol& s)
{
return ds << s.to_string();
}
private:
uint64_t m_value;
friend struct fc::reflector<symbol>;
}; // class symbol
inline bool operator== (const symbol& lhs, const symbol& rhs)
{
return lhs.value() == rhs.value();
}
inline bool operator!= (const symbol& lhs, const symbol& rhs)
{
return lhs.value() != rhs.value();
}
inline bool operator< (const symbol& lhs, const symbol& rhs)
{
return lhs.value() < rhs.value();
}
inline bool operator> (const symbol& lhs, const symbol& rhs)
{
return lhs.value() > rhs.value();
}
} // namespace chain
} // namespace eosio
namespace fc {
inline void to_variant(const eosio::chain::symbol& var, fc::variant& vo) { vo = var.to_string(); }
inline void from_variant(const fc::variant& var, eosio::chain::symbol& vo) {
vo = eosio::chain::symbol::from_string(var.get_string());
}
}
FC_REFLECT(eosio::chain::symbol, (m_value))
......@@ -134,18 +134,66 @@ namespace eosio { namespace chain {
struct transaction : public transaction_header {
vector<action> actions;
transaction_id_type id()const;
digest_type sig_digest( const chain_id_type& chain_id )const;
transaction_id_type id()const;
digest_type sig_digest( const chain_id_type& chain_id )const;
flat_set<public_key_type> get_signature_keys( const vector<signature_type>& signatures, const chain_id_type& chain_id )const;
};
struct signed_transaction : public transaction {
vector<signature_type> signatures;
struct signed_transaction : public transaction
{
signed_transaction() = default;
// signed_transaction( const signed_transaction& ) = default;
// signed_transaction( signed_transaction&& ) = default;
signed_transaction( transaction&& trx, const vector<signature_type>& signatures)
: transaction(std::forward<transaction>(trx))
, signatures(signatures)
{
}
vector<signature_type> signatures;
const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id);
signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const;
flat_set<public_key_type> get_signature_keys( const chain_id_type& chain_id )const;
};
struct packed_transaction {
enum compression_type {
none,
zlib,
};
packed_transaction() = default;
explicit packed_transaction(const transaction& t, compression_type _compression = none)
{
set_transaction(t, _compression);
}
explicit packed_transaction(const signed_transaction& t, compression_type _compression = none)
:signatures(t.signatures)
{
set_transaction(t, _compression);
}
explicit packed_transaction(signed_transaction&& t, compression_type _compression = none)
:signatures(std::move(t.signatures))
{
set_transaction(t, _compression);
}
vector<signature_type> signatures;
compression_type compression;
bytes data;
bytes get_raw_transaction()const;
transaction get_transaction()const;
signed_transaction get_signed_transaction()const;
void set_transaction(const transaction& t, compression_type _compression = none);
};
/**
* When a transaction is generated it can be scheduled to occur
......@@ -207,6 +255,8 @@ FC_REFLECT( eosio::chain::action, (account)(name)(authorization)(data) )
FC_REFLECT( eosio::chain::transaction_header, (expiration)(region)(ref_block_num)(ref_block_prefix) )
FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (actions) )
FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures) )
FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib))
FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(data) )
FC_REFLECT_DERIVED( eosio::chain::deferred_transaction, (eosio::chain::transaction), (sender_id)(sender)(execute_after) )
FC_REFLECT_ENUM( eosio::chain::data_access_info::access_type, (read)(write))
FC_REFLECT( eosio::chain::data_access_info, (type)(code)(scope)(sequence))
......
......@@ -8,43 +8,62 @@
namespace eosio { namespace chain {
struct transaction_metadata {
transaction_metadata( const transaction& t )
:trx(t)
,id(trx.id()) {}
transaction_metadata( const transaction& t, const time_point& published, const account_name& sender, uint32_t sender_id, const char* generated_data, size_t generated_size )
:trx(t)
,id(trx.id())
,published(published)
,sender(sender),sender_id(sender_id),generated_data(generated_data),generated_size(generated_size)
{}
transaction_metadata( const signed_transaction& t, chain_id_type chainid, const time_point& published )
:trx(t)
,id(trx.id())
,bandwidth_usage( fc::raw::pack_size(t) )
,published(published)
{ }
const transaction& trx;
transaction_id_type id;
optional<flat_set<public_key_type>> signing_keys;
uint32_t region_id = 0;
uint32_t cycle_index = 0;
uint32_t shard_index = 0;
uint32_t bandwidth_usage = 0;
time_point published;
// things for processing deferred transactions
optional<account_name> sender;
uint32_t sender_id = 0;
const char* generated_data = nullptr;
size_t generated_size = 0;
// scopes available to this transaction if we are applying a block
optional<const vector<shard_lock>*> allowed_read_locks;
optional<const vector<shard_lock>*> allowed_write_locks;
class transaction_metadata {
// transaction_metadata( const transaction& t )
// :trx(t)
// ,id(trx.id()) {}
public:
transaction_metadata( const transaction& t, const time_point& published, const account_name& sender, uint32_t sender_id, const char* raw_data, size_t raw_size )
:id(t.id())
,published(published)
,sender(sender),sender_id(sender_id),raw_data(raw_data),raw_size(raw_size),_trx(&t)
{}
transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published );
transaction_metadata( transaction_metadata && ) = default;
transaction_metadata& operator= (transaction_metadata &&) = default;
// things for packed_transaction
optional<bytes> raw_trx;
optional<transaction> decompressed_trx;
// things for signed/packed transactions
optional<flat_set<public_key_type>> signing_keys;
transaction_id_type id;
uint32_t region_id = 0;
uint32_t cycle_index = 0;
uint32_t shard_index = 0;
uint32_t bandwidth_usage = 0;
time_point published;
// things for processing deferred transactions
optional<account_name> sender;
uint32_t sender_id = 0;
// packed form to pass to contracts if needed
const char* raw_data = nullptr;
size_t raw_size = 0;
vector<char> packed_trx;
// scopes available to this transaction if we are applying a block
optional<const vector<shard_lock>*> allowed_read_locks;
optional<const vector<shard_lock>*> allowed_write_locks;
const transaction& trx() const{
if (decompressed_trx) {
return *decompressed_trx;
} else {
return *_trx;
}
}
static digest_type calculate_transaction_merkle_root( const vector<transaction_metadata>& metas );
private:
const transaction* _trx;
};
} } // eosio::chain
......
......@@ -61,6 +61,8 @@ namespace eosio { namespace chain {
using std::make_pair;
using std::move;
using std::forward;
using std::to_string;
using std::all_of;
using fc::path;
using fc::smart_ref;
......@@ -118,6 +120,7 @@ namespace eosio { namespace chain {
action_code_object_type,
key_value_object_type,
key128x128_value_object_type,
key64x64_value_object_type,
action_permission_object_type,
global_property_object_type,
dynamic_global_property_object_type,
......@@ -170,6 +173,7 @@ FC_REFLECT_ENUM(eosio::chain::object_type,
(action_code_object_type)
(key_value_object_type)
(key128x128_value_object_type)
(key64x64_value_object_type)
(action_permission_object_type)
(global_property_object_type)
(dynamic_global_property_object_type)
......
#pragma once
namespace IR {
struct Module;
};
namespace eosio { namespace chain {
//Throws if something in the module violates
void validate_eosio_wasm_constraints(const IR::Module& m);
}}
......@@ -28,8 +28,8 @@ struct wasm_cache::entry {
struct wasm_context {
wasm_context(wasm_cache::entry &code, apply_context& ctx) : code(code), context(ctx)
{
//initialize to minimum bytes and limit this to 32 bit space
sbrk_bytes = (1 << IR::numBytesPerPageLog2) > UINT32_MAX ? UINT32_MAX : 1 << IR::numBytesPerPageLog2;
MemoryInstance* default_mem = Runtime::getDefaultMemory(code.instance);
sbrk_bytes = default_mem ? Runtime::getMemoryNumPages(default_mem) << IR::numBytesPerPageLog2 : 0;
}
wasm_cache::entry& code;
apply_context& context;
......
......@@ -2,15 +2,16 @@
#include <fc/variant.hpp>
#include <boost/algorithm/string.hpp>
#include <fc/exception/exception.hpp>
#include <eosio/chain/exceptions.hpp>
namespace eosio { namespace chain {
void name::set( const char* str ) {
try {
const auto len = strnlen(str,14);
FC_ASSERT( len <= 13 );
EOS_ASSERT( len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name",string(str)) );
value = string_to_name(str);
FC_ASSERT( to_string() == string(str), "name not properly normalized", ("name",string(str))("normalized",to_string()) );
EOS_ASSERT( to_string() == string(str), name_type_exception, "Name not properly normalized (name: ${name}, normalized: ${normalized}) ", ("name",string(str))("normalized",to_string()) );
}FC_CAPTURE_AND_RETHROW( (str) ) }
name::operator string()const {
......
......@@ -6,9 +6,9 @@ add_executable(chain_unit_test
test.cpp
block_test.cpp
name_test.cpp
)
transaction_test.cpp)
target_include_directories(chain_unit_test PRIVATE ${Boost_INCLUDE_DIRS})
target_compile_definitions(chain_unit_test PRIVATE "BOOST_TEST_DYN_LINK=1")
target_link_libraries(chain_unit_test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} eosio_chain)
target_link_libraries(chain_unit_test eosio_chain)
add_test(chain_unit_test chain_unit_test)
#include <boost/test/unit_test.hpp>
#include <eosio/chain/transaction.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/exceptions.hpp>
#include <fc/io/raw.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/algorithm/string/predicate.hpp>
using namespace eosio::chain;
using namespace std;
namespace bio = boost::iostreams;
struct test_action {
string value;
static account_name get_account() {
return N(test.account);
}
static action_name get_name() {
return N(test.action);
}
};
// 3x deflated bomb
// we only inflate once but this makes this very small to store in this test case as long as we decompress it 2x before use
static const char deflate_bomb[] = "789c012e00d1ff789cabb8f5f6a021230303c3a1055ffd7379e417308c8251300a46c1281805a360d8837d6c8c0f18180190e708b7ec451357";
/**
* Utility predicate to check whether an EOS exception has the given message/code
*/
template<typename E>
struct exception_is {
exception_is(string expected)
:expected(expected)
{}
bool operator()( const fc::exception& ex ) {
auto message = ex.get_log().at(0).get_message();
return ex.code() == E::code_value && boost::algorithm::ends_with(message, expected);
}
string expected;
};
FC_REFLECT(test_action, (value));
BOOST_AUTO_TEST_SUITE(transaction_test)
BOOST_AUTO_TEST_CASE(compress_transaction)
{
try {
std::string expected = "78da63606060d8bf7ff5eab2198ace8c13962fe3909cb0f114835aa9248866044a3284784ef402d12bde1a19090a1425e6a5e4e72aa42496242a64a416a50200a9d114bb";
transaction trx;
trx.region = 0xBFBFU;
trx.ref_block_num = 0xABABU;
trx.ref_block_prefix = 0x43219876UL;
trx.actions.emplace_back(vector<permission_level>{{N(decomp), config::active_name}},
test_action {"random data here"});
packed_transaction t;
t.set_transaction(trx, packed_transaction::zlib);
auto actual = fc::to_hex(t.data);
BOOST_CHECK_EQUAL(expected, actual);
} FC_LOG_AND_RETHROW();
}
BOOST_AUTO_TEST_CASE(decompress_transaction)
{
try {
transaction expected;
expected.region = 0xBFBFU;
expected.ref_block_num = 0xABABU;
expected.ref_block_prefix = 0x43219876UL;
expected.actions.emplace_back(vector<permission_level>{{N(decomp), config::active_name}},
test_action {"random data here"});
char compressed_tx_raw[] = "78da63606060d8bf7ff5eab2198ace8c13962fe3909cb0f114835aa9248866044a3284784ef402d12bde1a19090a1425e6a5e4e72aa42496242a64a416a50200a9d114bb";
packed_transaction t;
t.data.resize((sizeof(compressed_tx_raw) - 1) / 2);
fc::from_hex(compressed_tx_raw, t.data.data(), t.data.size());
t.compression= packed_transaction::zlib;
auto actual = t.get_transaction();
BOOST_CHECK_EQUAL(expected.region, actual.region);
BOOST_CHECK_EQUAL(expected.ref_block_num, actual.ref_block_num);
BOOST_CHECK_EQUAL(expected.ref_block_prefix, actual.ref_block_prefix);
BOOST_REQUIRE_EQUAL(expected.actions.size(), actual.actions.size());
BOOST_CHECK_EQUAL((string)expected.actions[0].name, (string)actual.actions[0].name);
BOOST_CHECK_EQUAL((string)expected.actions[0].account, (string)actual.actions[0].account);
BOOST_REQUIRE_EQUAL(expected.actions[0].authorization.size(), actual.actions[0].authorization.size());
BOOST_CHECK_EQUAL((string)expected.actions[0].authorization[0].actor, (string)actual.actions[0].authorization[0].actor);
BOOST_CHECK_EQUAL((string)expected.actions[0].authorization[0].permission, (string)actual.actions[0].authorization[0].permission);
BOOST_REQUIRE_EQUAL(fc::to_hex(expected.actions[0].data), fc::to_hex(actual.actions[0].data));
} FC_LOG_AND_RETHROW();
}
BOOST_AUTO_TEST_CASE(decompress_bomb)
{
try {
bytes bomb_bytes;
bomb_bytes.resize((sizeof(deflate_bomb) - 1) / 2);
fc::from_hex(deflate_bomb, bomb_bytes.data(), bomb_bytes.size());
packed_transaction t;
// double inflate the bomb into the tx data
bio::filtering_ostream decomp;
decomp.push(bio::zlib_decompressor());
decomp.push(bio::zlib_decompressor());
decomp.push(bio::back_inserter(t.data));
bio::write(decomp, bomb_bytes.data(), bomb_bytes.size());
bio::close(decomp);
t.compression= packed_transaction::zlib;
BOOST_REQUIRE_EXCEPTION(t.get_transaction(), fc::exception, exception_is<tx_decompression_error>("Exceeded maximum decompressed transaction size"));
} FC_LOG_AND_RETHROW();
}
BOOST_AUTO_TEST_SUITE_END()
此差异已折叠。
#include <eosio/chain/transaction_metadata.hpp>
#include <eosio/chain/merkle.hpp>
#include <fc/io/raw.hpp>
namespace eosio { namespace chain {
transaction_metadata::transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published )
:raw_trx(t.get_raw_transaction())
,decompressed_trx(fc::raw::unpack<transaction>(*raw_trx))
,id(decompressed_trx->id())
,bandwidth_usage( (uint32_t)fc::raw::pack_size(t) )
,published(published)
,raw_data(raw_trx->data())
,raw_size(raw_trx->size())
{ }
digest_type transaction_metadata::calculate_transaction_merkle_root( const vector<transaction_metadata>& metas ) {
vector<digest_type> ids;
ids.reserve(metas.size());
for( const auto& t : metas ) {
ids.emplace_back(t.id);
}
return merkle( std::move(ids) );
}
} } // eosio::chain
\ No newline at end of file
此差异已折叠。
此差异已折叠。
file(GLOB HEADERS "include/eosio/tester/*.hpp")
file(GLOB HEADERS "include/eosio/testing/*.hpp")
## SORT .cpp by most likely to change / break compile
add_library( eosio_testing
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册