未验证 提交 4e967913 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge branch 'master' into DAWN-692

......@@ -22,7 +22,7 @@ set(VERSION_MAJOR 3)
set(VERSION_MINOR 0)
set(VERSION_PATCH 1)
set( CLI_CLIENT_EXECUTABLE_NAME eosioc )
set( CLI_CLIENT_EXECUTABLE_NAME cleos )
set( GUI_CLIENT_EXECUTABLE_NAME eosio )
set( CUSTOM_URL_SCHEME "gcs" )
set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" )
......
......@@ -4,22 +4,18 @@ RUN git clone -b master --depth 1 https://github.com/EOSIO/eos.git --recursive \
&& cd eos \
&& cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DSecp256k1_ROOT_DIR=/usr/local \
&& cmake --build /tmp/build --target install \
&& mkdir -p /opt/eosio/ && cp -r /tmp/build/bin /opt/eosio/bin && cp -r /tmp/build/contracts /contracts \
&& rm -rf /tmp/build && rm -rf /eos
&& cmake --build /tmp/build --target install
FROM ubuntu:16.04
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl && rm -rf /var/lib/apt/lists/*
COPY --from=builder /opt/eosio /opt/eosio
COPY --from=builder /contracts /contracts
COPY start_eosiod.sh /opt/eosio/bin/
COPY config.ini /
COPY genesis.json /
COPY --from=builder /usr/local/lib/* /usr/local/lib/
COPY --from=builder /tmp/build/bin /opt/eosio/bin
COPY --from=builder /tmp/build/contracts /contracts
COPY --from=builder /eos/Docker/config.ini /eos/genesis.json /
COPY start_nodeos.sh /opt/eosio/bin/start_nodeos.sh
ENV EOSIO_ROOT=/opt/eosio
RUN chmod +x /opt/eosio/bin/start_eosiod.sh
RUN chmod +x /opt/eosio/bin/start_nodeos.sh
ENV LD_LIBRARY_PATH /usr/local/lib
VOLUME /opt/eosio/bin/data-dir
ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
......@@ -16,22 +16,22 @@ cd eos/Docker
docker build . -t eosio/eos
```
## Start eosiod docker container only
## Start nodeos docker container only
```bash
docker run --name eosiod -p 8888:8888 -p 9876:9876 -t eosio/eos start_eosiod.sh arg1 arg2
docker run --name nodeos -p 8888:8888 -p 9876:9876 -t eosio/eos start_nodeos.sh arg1 arg2
```
By default, all data is persisted in a docker volume. It can be deleted if the data is outdated or corrupted:
``` bash
$ docker inspect --format '{{ range .Mounts }}{{ .Name }} {{ end }}' eosiod
$ docker inspect --format '{{ range .Mounts }}{{ .Name }} {{ end }}' nodeos
fdc265730a4f697346fa8b078c176e315b959e79365fc9cbd11f090ea0cb5cbc
$ docker volume rm fdc265730a4f697346fa8b078c176e315b959e79365fc9cbd11f090ea0cb5cbc
```
Alternately, you can directly mount host directory into the container
```bash
docker run --name eosiod -v /path-to-data-dir:/opt/eosio/bin/data-dir -p 8888:8888 -p 9876:9876 -t eosio/eos start_eosiod.sh arg1 arg2
docker run --name nodeos -v /path-to-data-dir:/opt/eosio/bin/data-dir -p 8888:8888 -p 9876:9876 -t eosio/eos start_nodeos.sh arg1 arg2
```
## Get chain info
......@@ -40,29 +40,29 @@ docker run --name eosiod -v /path-to-data-dir:/opt/eosio/bin/data-dir -p 8888:88
curl http://127.0.0.1:8888/v1/chain/get_info
```
## Start both eosiod and walletd containers
## Start both nodeos and walletd containers
```bash
docker-compose up
```
After `docker-compose up`, two services named eosiod and walletd will be started. eosiod service would expose ports 8888 and 9876 to the host. walletd service does not expose any port to the host, it is only accessible to eosioc when runing eosioc is running inside the walletd container as described in "Execute eosioc commands" section.
After `docker-compose up`, two services named nodeos and walletd will be started. nodeos service would expose ports 8888 and 9876 to the host. walletd service does not expose any port to the host, it is only accessible to cleos when runing cleos is running inside the walletd container as described in "Execute cleos commands" section.
### Execute eosioc commands
### Execute cleos commands
You can run the `eosioc` commands via a bash alias.
You can run the `cleos` commands via a bash alias.
```bash
alias eosioc='docker-compose exec walletd /opt/eosio/bin/eosioc -H eosiod'
eosioc get info
eosioc get account inita
alias cleos='docker-compose exec walletd /opt/eosio/bin/cleos -H nodeos'
cleos get info
cleos get account inita
```
Upload sample exchange contract
```bash
eosioc set contract exchange contracts/exchange/exchange.wast contracts/exchange/exchange.abi
cleos set contract exchange contracts/exchange/exchange.wast contracts/exchange/exchange.abi
```
If you don't need walletd afterwards, you can stop the walletd service using
......@@ -78,9 +78,9 @@ You can use docker compose override file to change the default configurations. F
version: "2"
services:
eosiod:
nodeos:
volumes:
- eosiod-data-volume:/opt/eosio/bin/data-dir
- nodeos-data-volume:/opt/eosio/bin/data-dir
- ./config2.ini:/opt/eosio/bin/data-dir/config.ini
```
......@@ -95,5 +95,5 @@ docker-compose up
The data volume created by docker-compose can be deleted as follows:
```bash
docker volume rm docker_eosiod-data-volume
docker volume rm docker_nodeos-data-volume
```
#!/bin/bash
# Usage:
# Go into cmd loop: sudo ./eosioc.sh
# Run single cmd: sudo ./eosioc.sh <eosioc paramers>
# Go into cmd loop: sudo ./cleos.sh
# Run single cmd: sudo ./cleos.sh <cleos paramers>
PREFIX="docker exec docker_eosiod_1 eosioc"
PREFIX="docker exec docker_nodeos_1 cleos"
if [ -z $1 ] ; then
while :
do
read -e -p "eosioc " cmd
read -e -p "cleos " cmd
history -s "$cmd"
$PREFIX $cmd
done
......
version: "2"
version: "3"
services:
eosiod:
nodeos:
build:
context: .
image: eosio/eos
command: /opt/eosio/bin/start_eosiod.sh
command: /opt/eosio/bin/start_nodeos.sh
ports:
- 8888:8888
- 9876:9876
expose:
- "8888"
volumes:
- eosiod-data-volume:/opt/eosio/bin/data-dir
- nodeos-data-volume:/opt/eosio/bin/data-dir
walletd:
image: eosio/eos
command: /opt/eosio/bin/eosiowd
links:
- eosiod
- nodeos
volumes:
- walletd-data-volume:/opt/eosio/bin/data-dir
volumes:
eosiod-data-volume:
nodeos-data-volume:
walletd-data-volume:
......@@ -36,4 +36,4 @@ else
CONFIG_DIR=""
fi
exec /opt/eosio/bin/eosiod $CONFIG_DIR $@
exec /opt/eosio/bin/nodeos $CONFIG_DIR $@
此差异已折叠。
......@@ -23,8 +23,6 @@ add_subdirectory(test_api)
add_subdirectory(test_api_mem)
add_subdirectory(test_api_db)
add_subdirectory(test_api_multi_index)
add_subdirectory(simpledb)
#add_subdirectory(storage)
#add_subdirectory(social)
add_subdirectory(eosio.bios)
add_subdirectory(noop)
......
......@@ -6,7 +6,6 @@
#include <eosiolib/eos.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/reflect.hpp>
#include <eosiolib/generic_currency.hpp>
......
......@@ -4,4 +4,3 @@
*/
#include <eosiolib/eosio.hpp>
#include <eosiolib/db.hpp>
......@@ -4,7 +4,6 @@
*/
#include <eosiolib/eosio.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/reflect.hpp>
#include <eosiolib/print.hpp>
......
/**
* @file db.h
* @file datastream.hpp
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
......
此差异已折叠。
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/db.h>
namespace eosio {
/**
* @defgroup databaseCpp Database C++ API
* @brief C++ APIs for interfacing with the database. It is based on pimpl idiom.
* @ingroup database
*/
template<typename T>
struct table_impl_obj {};
template<int Primary, int Secondary>
struct table_impl{};
template<>
struct table_impl<sizeof(uint128_t),sizeof(uint128_t)> {
static int32_t front_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return front_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t back_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return back_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t load_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return load_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t next_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return next_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t previous_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return previous_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t upper_bound_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return upper_bound_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t lower_bound_primary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return lower_bound_primary_i128i128( code, scope, table_n, data, len );
}
static int32_t front_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return front_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t back_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return back_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t load_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return load_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t next_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return next_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t previous_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return previous_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t upper_bound_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return upper_bound_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t lower_bound_secondary( uint64_t code, uint64_t scope, uint64_t table_n, void* data, uint32_t len ) {
return lower_bound_secondary_i128i128( code, scope, table_n, data, len );
}
static int32_t remove( uint64_t scope, uint64_t table_n, const void* data ) {
return remove_i128i128( scope, table_n, data );
}
static int32_t store( account_name scope, table_name table_n, account_name bta, const void* data, uint32_t len ) {
return store_i128i128( scope, table_n, bta, data, len );
}
static int32_t update( account_name scope, table_name table_n, account_name bta, const void* data, uint32_t len ) {
return update_i128i128( scope, table_n, bta, data, len );
}
};
template<uint64_t code, uint64_t scope, uint64_t table_n, uint64_t bta, typename Record, typename PrimaryType, typename SecondaryType = void>
struct table {
private:
typedef table_impl<sizeof( PrimaryType ), sizeof( SecondaryType )> impl;
static_assert( sizeof(PrimaryType) + sizeof(SecondaryType) <= sizeof(Record), "invalid template parameters" );
public:
typedef PrimaryType primary;
typedef SecondaryType secondary;
/**
* @brief Primary Index of the Table
*/
struct primary_index {
/**
* @param r - reference to a record to store the front record based on primary index.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool front( Record& r, uint64_t s = scope ) {
return impl::front_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to store the back record based on primary index.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool back( Record& r, uint64_t s = scope ) {
return impl::back_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to store next value; must be initialized with current.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool next( Record& r, uint64_t s = scope ) {
return impl::next_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to store previous value; must be initialized with current.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool previous( Record& r, uint64_t s = scope ) {
return impl::previous_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param p - reference to primary key to load; must be initialized with a value;
* @param r - reference to a record to load the value to.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) {
*reinterpret_cast<PrimaryType*>(&r) = p;
return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param p - reference to primary key to get the lower bound of; must be initialized with a value;
* @param r - reference to a record to load the value to.
*
* @return true if successful read.
*/
static bool lower_bound( const PrimaryType& p, Record& r ) {
return impl::lower_bound_primary( code, scope, table_n, &p &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param p - reference to primary key to get the upper bound of; must be initialized with a value;
* @param r - reference to a record to load the value to.
*
* @return true if successful read.
*/
static bool upper_bound( const PrimaryType& p, Record& r ) {
return impl::upper_bound_primary( code, scope, table_n, &p &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to remove from table;
* @param s - account scope. default is current scope of the class
*
* @return true if successfully removed;
*/
static bool remove( const Record& r, uint64_t s = scope ) {
return impl::remove( s, table_n, &r ) != 0;
}
};
/**
* @brief Secondary Index of the Table
*/
struct secondary_index {
/**
* @param r - reference to a record to store the front record based on secondary index.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool front( Record& r, uint64_t s = scope ) {
return impl::front_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to store the back record based on secondary index.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool back( Record& r, uint64_t s = scope ) {
return impl::back_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to return the next record .
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool next( Record& r, uint64_t s = scope ) {
return impl::next_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to return the next record.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool previous( Record& r, uint64_t s = scope ) {
return impl::previous_secondary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param p - reference to secondary index key
* @param r - reference to record to hold the value
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool get( const SecondaryType& p, Record& r, uint64_t s = scope ) {
return impl::load_secondary( code, s, table_n, &p &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param p - reference to secondary key to get the lower bound of; must be initialized with a value;
* @param r - reference to a record to load the value to.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool lower_bound( const SecondaryType& p, Record& r, uint64_t s = scope ) {
return impl::lower_bound_secondary( code, s, table_n, &p &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param p - reference to secondary key to get the upper bound of; must be initialized with a value;
* @param r - reference to a record to load the value to.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool upper_bound( const SecondaryType& p, Record& r, uint64_t s = scope ) {
return impl::upper_bound_secondary( code, s, table_n, &p &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @param r - reference to a record to be removed.
* @param s - account scope. default is current scope of the class
*
* @return true if successfully removed.
*/
static bool remove( const Record& r, uint64_t s = scope ) {
return impl::remove( s, table_n, &r ) != 0;
}
};
/**
* @brief Fetches a record from the table.
* @details Fetches a record from the table.
* @param p - reference to primary key to retrieve
* @param r - reference to a record to load the value to.
* @param s - account scope. default is current scope of the class
*
* @return true if successful read.
*/
static bool get( const PrimaryType& p, Record& r, uint64_t s = scope ) {
*reinterpret_cast<PrimaryType*>(&r) = p;
return impl::load_primary( code, s, table_n, &r, sizeof(Record) ) == sizeof(Record);
}
/**
* @brief Store a record in the table.
* @details Store a record in the table.
* @param r - reference to a record to store.
* @param s - account scope. default is current scope of the class
*
* @return true if successful store.
*/
static bool store( const Record& r, uint64_t s = scope, uint64_t b = bta ) {
eosio_assert( impl::store( s, table_n, b, &r, sizeof(r) ), "error storing record" );
return true;
}
/**
* @brief Update a record in the table.
* @details Update a record in the table.
* @param r - reference to a record to update.
* @param s - account scope. default is current scope of the class
*
* @return true if successful update.
*/
static bool update( const Record& r, uint64_t s = scope, uint64_t b = bta ) {
eosio_assert( impl::update( s, table_n, b, &r, sizeof(r) ), "error updating record" );
return true;
}
/**
* @brief Remove a record from the table.
* @details Remove a record from the table.
* @param r - reference to a record to remove.
* @param s - account scope. default is current scope of the class
*
* @return true if successful remove.
*/
static bool remove( const Record& r, uint64_t s = scope ) {
return impl::remove( s, table_n, &r ) != 0;
}
};
/// @}
} // namespace eosio
#include "memory.hpp"
void* sbrk(size_t num_bytes) {
constexpr uint32_t NBPPL2 = 16U;
constexpr uint32_t NBBP = 65536U;
static bool initialized;
static uint32_t sbrk_bytes;
if(!initialized) {
sbrk_bytes = __builtin_wasm_current_memory() * NBBP;
initialized = true;
}
if(num_bytes > INT32_MAX)
return reinterpret_cast<void*>(-1);
//uint32_t num_bytes = (uint32_t)num_bytesI;
const uint32_t prev_num_bytes = sbrk_bytes;
const uint32_t current_pages = __builtin_wasm_current_memory();
// round the absolute value of num_bytes to an alignment boundary
num_bytes = (num_bytes + 7U) & ~7U;
// update the number of bytes allocated, and compute the number of pages needed
const uint32_t num_desired_pages = (sbrk_bytes + num_bytes + NBBP - 1) >> NBPPL2;
if(num_desired_pages > current_pages) {
//unfortuately clang4 doesn't provide the return code of grow_memory, that's why need
//to go back around and double check current_memory to make sure it has actually grown!
__builtin_wasm_grow_memory(num_desired_pages - current_pages);
if(num_desired_pages != __builtin_wasm_current_memory())
return reinterpret_cast<void*>(-1);
}
sbrk_bytes += num_bytes;
return reinterpret_cast<void*>(prev_num_bytes);
}
namespace eosio {
using ::memset;
......
......@@ -7,7 +7,7 @@
#include <eosiolib/memory.h>
#include <eosiolib/print.hpp>
#include <unistd.h>
void* sbrk(size_t num_bytes);
extern "C" {
......
......@@ -85,7 +85,8 @@ extern "C" {
* printd(*(uint64_t*)(&double_value)); // Output: 0.5
* @endcode
*/
void printd(double value);
void printdf(double value);
void printff(float value);
void printdi(int64_t value);
/**
......
......@@ -33,7 +33,8 @@ namespace eosio {
inline void print( int64_t num ) {
printi(num);
}
inline void print( double d ) { printdi( *((int64_t*)&d) ); }
inline void print( double d ) { printdf( d ); }
inline void print( float f ) { printff( f ); }
/**
* Prints 32 bit unsigned integer as a 64 bit unsigned integer
......
......@@ -31,6 +31,12 @@ extern "C" {
*/
void eosio_assert( uint32_t test, const char* cstr );
/**
* This method will abort execution of wasm without failing the contract. This
* is used to bypass all cleanup / destructors that would normally be called.
*/
[[noreturn]] void eosio_exit( int32_t code );
/**
* Returns the time in seconds from 1970 of the last accepted block (not the block including this action)
* @brief Get time of the last accepted block
......
#pragma once
#include <eosiolib/system.h>
#include <eosiolib/db.h>
#include <eosiolib/datastream.hpp>
namespace eosio {
/**
* @tparam DefaultScope - the default
* @tparam TableName - the name of the table with rows of type T
* @tparam T - a struct where the first 8 bytes are used as primary/unique key
*/
template<uint64_t DefaultScope, uint64_t TableName, uint64_t BillToAccount, typename T>
class table64
{
public:
static bool exists( uint64_t key, scope_name scope = DefaultScope) {
auto read = load_i64( DefaultScope, scope, TableName, (char*)&key, sizeof(key) );
return read > 0;
}
static T get( uint64_t key, scope_name scope = DefaultScope ) {
char temp[1024];
*reinterpret_cast<uint64_t *>(temp) = key;
auto read = load_i64( DefaultScope, scope , TableName, temp, sizeof(temp) );
eosio_assert( read > 0, "key does not exist" );
datastream<const char*> ds(temp, uint32_t(read) );
T result;
ds >> result;
return result;
}
static T get_or_create( uint64_t key, scope_name scope = DefaultScope, const T& def = T() ) {
char temp[1024];
*reinterpret_cast<uint64_t *>(temp) = key;
auto read = load_i64( DefaultScope, scope, TableName, temp, sizeof(temp) );
if( read < 0 ) {
set( def, scope );
return def;
}
datastream<const char*> ds(temp, uint32_t(read) );
T result;
ds >> result;
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, uint32_t(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];
eosio_assert( size <= 1024, "singleton too big to store" );
datastream<char*> ds( buf, size );
ds << value;
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, uint64_t BillToAccount, 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 primary_upper_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 = upper_bound_primary_i64i64i64( Code, _scope, TableName,
(char*)temp, sizeof(temp) );
if( read <= 0 ) {
return false;
}
result = unpack<T>( (char*)temp, sizeof(temp) );
return true;
}
bool next_primary( T& result, const T& current ) {
const uint64_t* keys = reinterpret_cast<const uint64_t*>(&current);
return primary_upper_bound(result, keys[0], keys[1], keys[2]);
}
void store( const T& value, account_name bill_to = BillToAccount ) {
char temp[1024];
datastream<char*> ds(temp, sizeof(temp) );
ds << value;
store_i64i64i64( _scope, TableName, bill_to, 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;
};
}
Pegged Derivitive Currency Design
-----------------------
# Pegged Derivative Currency Design
A Derivitive uses a price feed and collateral to enable two or
more parties to speculate on the future price of anything and to
settle their speculation in terms of the collateral.
A currency is designed to be a fungible and non-callable asset. A pegged Derivative currency, such as BitUSD, is backed by a cryptocurrency held as collateral. The "issuer" is "short" the dollar and extra-long the cryptocurrency. The buyer is simply long the dollar.
A currency is designed to be a fungible and non-callable asset.
A pegged derivitive currency, such as BitUSD, is backed by a cryptocurrency
held as collateral. The "issuer" is "short" the dollar and extra-long the cryptocurrency.
The buyer is simply long the dollar.
Background
----------
BitShares created the first working pegged asset system by allowing anyone to take out
a short position by posting collateral and issuing BitUSD at a minimum 1.5:1 collateral:debt
ratio. The least collateralized position was forced to provide liquidity for BitUSD holders
BitShares created the first working pegged asset system by allowing anyone to take out a short position by posting collateral and issuing BitUSD at a minimum 1.5:1 collateral:debt ratio. The **least collateralized position** was forced to provide liquidity for BitUSD holders
any time the market price fell more than a couple percent below the dollar (if the BitUSD holder opted to use forced liquidation).
To prevent abuse of the price feed, all forced liquidation was delayed.
In the event of a "black swan" all shorts have their positions liquidated at the price feed and all holders of BitUSD are only
promised a fixed redemption rate.
In the event of a "black swan" all shorts have their positions liquidated at the price feed and all holders of BitUSD are only promised a fixed redemption rate.
There are several problems with this design:
1. There is very poor liquidity in the BitUSD / BitShares market creating large spreads
1. There is very **poor liquidity** in the BitUSD / BitShares market creating **large spreads**
2. The shorts take all the risk and only profit when the price of BitShares rises
3. Blackswans are perminentant and very disruptive.
3. Blackswans are perpetual and very disruptive.
4. It is "every short for themselves"
5. Due to the risk/reward ratio the supply can be limited
6. The collateral requirements limit opportunity for leverage.
6. The **collateral requirements** limit opportunity for leverage.
New Approach
------------
We present a new approach to pegged assets where the short-positions cooperate to provide the
service of a pegged asset with high liquidity. They make money by encouraging people to trade
their pegged asset and earning income from the trading fees rather than seeking heavy leverage
service of a pegged asset with **high liquidity**. They make money by encouraging people to trade
their pegged asset and earning income **from the trading fees rather than seeking heavy leverage**
in a speculative market. They also generate money by earning interest on personal short positions.
The Setup Process
-----------------
An initial user deposits a collateral currency (C) into an smart contract and provides the initial
price feed. A new Debt token (D) is issued based upon the price feed and a 5:1 C:D ratio and the
issued tokens are deposited into the Bancor market maker. At this point in time there is 0 leverage by
the market maker because no D have been sold. The initial user is also issued exchange tokens E in the
An initial user deposits a Collateral Currency (C) into an smart contract and provides the initial
price feed. A new Debt token (D) is issued based upon the price feed and a 1.5:1 C:D ratio and the
issued tokens are deposited into the **Bancor market maker**. At this point in time there is 0 leverage by
the market maker because no D have been sold. The initial user is also issued exchange tokens (E) in the
market maker.
At this point people can buy E or D and the Bancor algorithm will provide liquidity between C, E, and D. Due to
the fees charged by the the market maker the value of E will increase in terms of C.
> Collateral currency = Smart Token/reserve of parent currency
>
> Issued tokens = Bounty Tokens (distributed to early holders / community supporters)
>
> Collateral Ratio (C:D) = reciprocal of Loan-to-Value Ratio (LTV)
Maintaining the Peg
-------------------
To maximize the utility of the D token, the market maker needs to maintain a narrow trading range of D vs the Dollar. The
more consistant and reliable this trading range is, the more people will be willing to hold and trade D. There are several
To maximize the utility of the D token, the market maker needs to maintain a **narrow trading range** of D vs the Dollar.
The more **consistant and reliable this trading range** is, the more people (arbitrageur) will be willing to hold and trade D. There are several
situations that can occur:
1. D is trading above a dollar +5%
a. Maker is fully collateralized at 5:1
- issue new D and deposit into maker such that collateral ratio is 5:1
b. Maker is not fully collateralized
- adjust the maker weights to lower the redemption prices (defending capital of maker), arb will probably prevent this reality.
a. Maker is fully collateralized `C:D>1.5`
- issue new D and deposit into maker such that collateral ratio is 1.5:1
b. Maker is not fully collateralized `C:D<1.5`
- adjust the maker weights to lower the redemption prices (defending capital of maker), arbitrageur will probably prevent this reality.
> Marker Weights = Connector Weights (in Bancor)
>
> Redemption Price: The price at which a bond may be repurchased by the issuer before maturity
2. D is selling for less than a dollar -5%
a. Maker is fully collateralized at more than 1.5:1
a. Maker is fully collateralized `C:D>1.5`
- adjust the maker weights to increase redemption prices
c. Maker is under collateralized less than 1.5:1
b. Maker is under collateralized `C:D<1.5`
```
- stop E -> C and E -> D trades.
- offer bonus on C->E and D->E trades.
- on D->E conversions take received D out of circulation rather than add to maker
- on D->E conversions take received D out of circulation rather than add to the market maker
- on C<->D conversion continue as normal
- stop attempting adjusting maker ratio to defend the price feed and let the price float unless price is above +1%
Value of E = C - D where D == all in circulation, so E->C conversions should always assume all outstanding
D was settled at current maker price. The result of such a conversion will lower the collateral ratio, unless they are forced
to buy and retire some D at the current ratio. The algorithm must ensure the individual selling E doesn't leave those holding E
worse-off from a D/E perspective. An individual buying E will create new D to maintain the same D/E ratio.
- stop attempting adjusting maker ratio to defend the price feed and let the price rise until above +1%
```
Value of E = C - D where D == all in circulation, so E->C conversions should always assume all outstanding D was **settled at current maker price**. The result of such a conversion will **raise the collateral ratio**, unless they are forced to buy and retire some D at the current ratio. The algorithm must ensure the individual selling E doesn't leave those holding E worse-off from a D/E perspective (doesnot reduce D to a large extent). An individual buying E will create new D to maintain the same D/E ratio.
This implies that when value of all outstanding D is greater than all C that E cannot be sold until the network
generates enough in trading fees to recaptialize the market. This is like a company with more debt than equity not allowing buybacks. In fact, E should
not be sellable any time the collateral ratio falls below 1.5:1. In exchanges like BitShares this is typical margin call
territory, but in this system holders of E have a chance at future liquidity if the situation improves. While E is not sellable
E can be purchased at a 10% discount to its theoretical value, this will dilute existing holders of E but will raise capital and
hopefully move E holders closer to eventual liquidity.
generates **enough in trading fees** to recaptialize the market. This is like a company with more debt than equity not allowing buybacks. In fact, **E should not be sellable any time the collateral ratio falls below 1.5:1**.
BitShares is typical **margin call** territory, but holders of E have a chance at future liquidity if the situation improves. While E is not sellable,
E can be purchased at a 10% discount to its theoretical value, this will dilute existing holders of E but will raise capital and hopefully move E holders closer to eventual liquidity.
Adjusting Bancor Ratios by Price Feed
-------------------------------------
The price feed informs the algorithm of significant deviations between the Bancor price and the target peg. The price feed
is necisarially a lagging indicator and may also factor in natural spreads between different exchanges. Therefore, the price
feed shall have no impact unless there is a significant deviation (5%). When such a deviation occurs, the ratio is adjusted such
that there is still a 4% difference. In other words, the price feed keeps the maker in the "channel" but does not attempt to
set the real-time prices. If there is a sudden change and the pricefeed differs from maker by 50% then after the adjustment it will
still differ by 4%.
The price feed informs the algorithm of significant deviations between the Bancor effective price and the target peg. The price feed is necessarily a lagging indicator and may also factor in natural spreads between different exchanges. Therefore, the price feed shall have no impact unless there is a significant deviation (5%). When such a deviation occurs, the ratio is automatically adjusted to 4%.
In other words, the price feed keeps the maker in the "channel" but does not attempt to set the real-time prices. If there is a sudden change and the price feed differs from maker by 50% then after the adjustment it will still differ by 4%.
> Effective Price = Connected Tokens exchanged / Smart Tokens exchanged
Summary
-------
Under this model holders of E are short the dollar and make money to recollateralize their positions via market activity. Anyone
selling E must realize the losses as a result of being short. Anyone buying E can get in to take their place at the current collateral ratio.
Under this model holders of E are short the dollar and make money to recollateralize their positions via market activity.
Anyone selling E must **realize the losses as a result of being short**.
Anyone buying E can get in to take their place at the current collateral ratio.
The value of E is equal to the value of a margin postion.
The value of E is equal to the value of a **margin postion**.
Anyone can buy E for a combination C and D equal to the current collateral ratio.
Anyone may sell E for a personal margin position with equal ratio of C and D
Anyone may buy E with a personal margin position
Anyone may sell E for a personal margin position with equal ratio of C and D.
Anyone may buy E with a personal margin position.
If they only have C, then they must use some of C to buy D first (which will move the price)
If they only have D, then they must use some of D to buy C first (which will also move the price)
If they only have C, then they must use some of C to buy D first (which will move the price).
If they only have D, then they must use some of D to buy C first (which will also move the price).
Anyone can buy and sell E based upon Bancor balances of C and (all D), they must sell their E for a combination of D and C at current ratio, then sell the C or D for the other.
Anytime collateral level falls below 1.5 selling E is blocked and buying of E is given a 10% bonus.
Anyone can convert D<->C using Bancor maker configured to maintain price within +/- 5% of the price feed.
Anytime collateral level falls below 1.5 selling E is blocked and buying of E is given a 10% bonus.
Anyone can convert D<->C using Bancor maker configured to maintain price within +/- 5% of the price feed.
......@@ -244,6 +244,8 @@ namespace eosio {
extern "C" {
void apply( uint64_t code, uint64_t action ) {
eosio::exchange( current_receiver() ).apply( code, action );
eosio::exchange ex( current_receiver() );
ex.apply( code, action );
eosio_exit(0);
}
}
#include <eosiolib/chain.h>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/singleton.hpp>
#include <eosiolib/table.hpp>
#include <eosiolib/vector.hpp>
#include <identity/identity.hpp>
......
file(GLOB ABI_FILES "*.abi")
add_wast_executable(TARGET simpledb
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
{
"types": [],
"structs": [{
"name": "record1",
"base": "",
"fields": [{
"name": "key",
"type": "uint64"
},{
"name": "u256",
"type": "uint256"
},{
"name": "u128",
"type": "uint128"
},{
"name": "u64",
"type": "uint64"
},{
"name": "u32",
"type": "uint32"
},{
"name": "u16",
"type": "uint16"
},{
"name": "u8",
"type": "uint8"
},{
"name": "i64",
"type": "int64"
},{
"name": "i32",
"type": "int32"
},{
"name": "i16",
"type": "int16"
},{
"name": "i8",
"type": "int8"
}
]
},{
"name": "insert_record1",
"base": "",
"fields": [{
"name": "r1",
"type": "record1"
}
]
},{
"name": "remove_record1",
"base": "",
"fields": [{
"name": "key",
"type": "uint64"
}
]
},{
"name": "record2",
"base": "",
"fields": [{
"name": "key1",
"type": "uint128"
},{
"name": "key2",
"type": "uint128"
}
]
},{
"name": "insert_record2",
"base": "",
"fields": [{
"name": "r2",
"type": "record2"
}
]
},{
"name": "remove_record2",
"base": "",
"fields": [{
"name": "key",
"type": "record2"
}
]
},{
"name": "record3",
"base": "",
"fields": [{
"name": "key1",
"type": "uint64"
},{
"name": "key2",
"type": "uint64"
},{
"name": "key3",
"type": "uint64"
}
]
},{
"name": "insert_record3",
"base": "",
"fields": [{
"name": "r3",
"type": "record3"
}
]
},{
"name": "remove_record3",
"base": "",
"fields": [{
"name": "key",
"type": "record3"
}
]
},{
"name": "key_value1",
"base": "",
"fields": [{
"name": "key",
"type": "string"
},{
"name": "value",
"type": "string"
}
]
},{
"name": "insert_keyvalue1",
"base": "",
"fields": [{
"name": "kv1",
"type": "key_value1"
}
]
},{
"name": "remove_keyvalue1",
"base": "",
"fields": [{
"name": "key",
"type": "string"
}
]
},{
"name": "complex_type",
"base": "",
"fields": [{
"name": "name",
"type": "string"
},{
"name": "age",
"type": "uint64"
}
]
},{
"name": "key_value2",
"base": "",
"fields": [{
"name": "key",
"type": "string"
},{
"name": "value",
"type": "complex_type"
}
]
},{
"name": "insert_keyvalue2",
"base": "",
"fields": [{
"name": "kv2",
"type": "key_value2"
}
]
},{
"name": "remove_keyvalue2",
"base": "",
"fields": [{
"name": "key",
"type": "string"
}
]
}
],
"actions": [{
"name": "insert1",
"type": "insert_record1"
},{
"name": "remove1",
"type": "remove_record1"
},{
"name": "insert2",
"type": "insert_record2"
},{
"name": "remove2",
"type": "remove_record2"
},{
"name": "insert3",
"type": "insert_record3"
},{
"name": "remove3",
"type": "remove_record3"
},{
"name": "insertkv1",
"type": "insert_keyvalue1"
},{
"name": "removekv1",
"type": "remove_keyvalue1"
},{
"name": "insertkv2",
"type": "insert_keyvalue2"
},{
"name": "removekv2",
"type": "remove_keyvalue2"
}
],
"tables": [{
"name": "record1",
"index_type": "i64",
"key_names": [
"key"
],
"key_types": [
"uint64"
],
"type": "record1"
},{
"name": "record2",
"index_type": "i128i128",
"key_names": [
"key1",
"key2"
],
"key_types": [
"uint128",
"uint128"
],
"type": "record2"
},{
"name": "record3",
"index_type": "i64i64i64",
"key_names": [
"key1",
"key2",
"key3"
],
"key_types": [
"uint64",
"uint64",
"uint64"
],
"type": "record3"
},{
"name": "keyvalue1",
"index_type": "str",
"key_names": [
"key"
],
"key_types": [
"string"
],
"type": "key_value1"
},{
"name": "keyvalue2",
"index_type": "str",
"key_names": [
"key"
],
"key_types": [
"string"
],
"type": "key_value2"
}
]
}
\ No newline at end of file
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <string>
#include <eosiolib/action.hpp>
#include <eosiolib/types.hpp>
#include <eosiolib/serialize.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/system.h>
using namespace eosio;
namespace simpledb {
template<uint64_t Val>
struct dispatchable {
constexpr static uint64_t action_name = Val;
};
//@abi table
struct record1 {
uint64_t key;
//uint256 u256;
uint128_t u128;
uint64_t u64;
uint32_t u32;
uint16_t u16;
uint8_t u8;
int64_t i64;
int32_t i32;
int16_t i16;
int8_t i8;
EOSLIB_SERIALIZE( record1, (key)(u128)(u64)(u32)(u16)(u8)(i64)(i32)(i16)(i8) )
};
//@abi action insert1
struct insert_record1 : dispatchable<N(insert1)> {
record1 r1;
void process() {
bytes b = eosio::pack(r1);
store_i64( N(simpledb), N(record1), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record1, (r1) )
};
//@abi action remove1
struct remove_record1 : dispatchable<N(remove1)> {
uint64_t key;
void process() {
remove_i64( N(simpledb), N(record1), (char *)this);
}
EOSLIB_SERIALIZE( remove_record1, (key) )
};
//@abi table
struct record2 {
uint128_t key1;
uint128_t key2;
EOSLIB_SERIALIZE( record2, (key1)(key2) )
};
//@abi action insert2
struct insert_record2 : dispatchable<N(insert2)> {
record2 r2;
void process() {
bytes b = eosio::pack(r2);
store_i128i128( N(simpledb), N(record2), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record2, (r2) )
};
//@abi action remove2
struct remove_record2 : dispatchable<N(remove2)> {
record2 key;
void process() {
bytes b = eosio::pack(key);
remove_i128i128( N(simpledb), N(record2), b.data());
}
EOSLIB_SERIALIZE( remove_record2, (key) )
};
//@abi table
struct record3 {
uint64_t key1;
uint64_t key2;
uint64_t key3;
EOSLIB_SERIALIZE( record3, (key1)(key2)(key3) )
};
//@abi action insert3
struct insert_record3 : dispatchable<N(insert3)> {
record3 r3;
void process() {
bytes b = eosio::pack(r3);
store_i128i128( N(simpledb), N(record3), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record3, (r3) )
};
//@abi action remove3
struct remove_record3 : dispatchable<N(remove3)> {
record3 key;
void process() {
bytes b = eosio::pack(key);
remove_i64i64i64( N(simpledb), N(record2), b.data());
}
EOSLIB_SERIALIZE( remove_record3, (key) )
};
//@abi table
struct key_value1 {
std::string key;
std::string value;
EOSLIB_SERIALIZE( key_value1, (key)(value) )
};
//@abi action insertkv1
struct insert_keyvalue1 : dispatchable<N(insertkv1)> {
key_value1 kv1;
void process() {
eosio_assert(false, "not implemented");
// bytes b = eosio::pack(kv1.value);
// store_str( N(simpledb), N(keyvalue1), N(simpledb), (char *)kv1.key.data(), kv1.key.size(), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_keyvalue1, (kv1) )
};
//@abi action removekv1
struct remove_keyvalue1 : dispatchable<N(removekv1)> {
std::string key;
void process() {
eosio_assert(false, "not implemented");
//remove_str( N(simpledb), N(keyvalue1), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue1, (key) )
};
struct complex_type {
std::string name;
uint64_t age;
EOSLIB_SERIALIZE( complex_type, (name)(age) )
};
//@abi table
struct key_value2 {
std::string key;
complex_type value;
EOSLIB_SERIALIZE( key_value2, (key)(value) )
};
//@abi action insertkv2
struct insert_keyvalue2 : dispatchable<N(insertkv2)> {
key_value2 kv2;
void process() {
eosio_assert(false, "not implemented");
// bytes b = eosio::pack(kv2.value);
// store_str( N(simpledb), N(keyvalue2), N(simpledb), (char *)kv2.key.data(), kv2.key.size(), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_keyvalue2, (kv2) )
};
//@abi action removekv2
struct remove_keyvalue2 : dispatchable<N(removekv2)> {
std::string key;
void process() {
remove_str( N(simpledb), N(keyvalue2), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue2, (key) )
};
template<typename ...Ts>
struct dispatcher_impl;
template<typename T>
struct dispatcher_impl<T> {
static bool dispatch(uint64_t action) {
if (action == T::action_name) {
unpack_action_data<T>().process();
return true;
}
return false;
}
};
template<typename T, typename ...Rem>
struct dispatcher_impl<T, Rem...> {
static bool dispatch(uint64_t action) {
return dispatcher_impl<T>::dispatch(action) || dispatcher_impl<Rem...>::dispatch(action);
}
};
using dispatcher = dispatcher_impl<insert_record1, remove_record1, insert_record2, insert_record3, insert_keyvalue1, insert_keyvalue2>;
}
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t act ) {
if (code == current_receiver()) {
auto action_processed = simpledb::dispatcher::dispatch(act);
eosio_assert(action_processed, "unknown action");
}
}
}
......@@ -3,6 +3,5 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eosio.hpp>
#include <eosiolib/db.hpp>
file(GLOB ABI_FILES "*.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_wast_executable(TARGET storage
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
{
"types": [{
"new_type_name": "account_name",
"type": "name"
}
],
"structs": [{
"name": "transfer",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"amount", "type":"uint64"}
]
},{
"name": "account",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"tokbalance", "type":"uint64"},
{"name":"quotausage", "type":"uint64"}
]
},{
"name": "link",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"eospath", "type":"string"},
{"name":"ipfspath", "type":"string"},
{"name":"size" , "type":"uint32"},
{"name":"store", "type":"uint8"},
{"name":"accept", "type":"uint8"},
{"name":"stake", "type":"uint64"},
{"name":"producer", "type":"account_name"}
]
}
],
"actions": [{
"name": "transfer",
"type": "transfer"
},{
"name": "setlink",
"type": "link"
},{
"name": "removelink",
"type": "string"
},{
"name": "acceptstore",
"type": "string"
},{
"name": "rejectstore",
"type": "string"
}
],
"tables": [{
"name": "account",
"type": "account",
"index_type": "i64",
"key_names" : ["account"],
"key_types" : ["account_name"]
},{
"name": "links",
"type" : "link",
"index_type": "str",
"key_names" : ["eospath"],
"key_types" : ["string"]
}
]
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include "storage.hpp"
namespace TOKEN_NAME {
void store_account( account_name name, const account& account_to_store ) {
if ( account_to_store.is_empty() ) {
accounts::remove( account_to_store, name );
} else {
accounts::store(account_to_store, name );
}
}
void apply_storage_transfer( const TOKEN_NAME::transfer& transfer_storage ) {
eosio::require_recipient( transfer_storage.to, transfer_storage.from );
eosio::require_auth( transfer_storage.from );
account from = get_account( transfer_storage.from );
account to = get_account( transfer_storage.to );
from.balance -= transfer_storage.quantity; /// token subtraction has underflow assertion
to.balance += transfer_storage.quantity; /// token addition has overflow assertion
store_account( transfer_storage.from, from );
store_account( transfer_storage.to, to );
}
bool validate_ipfspath( const char* ipfspath, uint32_t len ) {
// To be implemented
return true;
}
bool validate_eospath( const char* eospath, uint32_t len ) {
// To be implemented
return true;
}
uint32_t read_link_from_buffer( const char* buffer, uint32_t bufferlen,
TOKEN_NAME::link& link_to_read, uint32_t& eospathlen, uint32_t ipfspathlen ) {
// To be implemented
return 0;
}
void apply_storage_setlink() {
TOKEN_NAME::link link_to_set;
uint32_t eospathlen;
uint32_t ipfspathlen;
char tmp[4098];
auto bufferlen = read_action(tmp, 4098);
auto linklen = read_link_from_buffer( tmp, bufferlen, link_to_set, eospathlen, ipfspathlen );
eosio::require_recipient( link_to_set.owner );
eosio::require_auth( link_to_set.owner );
validate_ipfspath( link_to_set.ipfspath, ipfspathlen );
validate_eospath( link_to_set.eospath, eospathlen );
::store_str( current_receiver(), N(storage), link_to_set.eospath, eospathlen, (char*)&link_to_set, linklen );
}
void apply_storage_removelink( char* eospath, uint32_t eospathlen ) {
char tmp[4098];
auto len = ::load_str( current_receiver(), current_receiver(), N(storage), eospath, eospathlen, tmp, 4098 );
TOKEN_NAME::link link_to_remove;
uint32_t ipfspathlen;
len = read_link_from_buffer( tmp, len, link_to_remove, eospathlen, ipfspathlen );
eosio::require_auth( link_to_remove.owner );
uint32_t stake = link_to_remove.stake;
::remove_str( current_receiver(), N(storage), link_to_remove.eospath, eospathlen );
// Reduce Quota usage in account table
// How does producer know to free cached file?
}
void apply_storage_createstore( char* eospath, uint32_t eospathlen ) {
char tmp[4098];
auto len = ::load_str( current_receiver(), current_receiver(), N(storage), eospath, eospathlen, tmp, 4098 );
TOKEN_NAME::link link_to_create;
uint32_t ipfspathlen;
len = read_link_from_buffer( tmp, len, link_to_create, eospathlen, ipfspathlen );
// eosio::require_auth( producer )
// How do we validate the require_auth() is a producer?
// logic goes here to reduce number of tokens and increase quote used using bancor algorithm
link_to_create.accept = 1;
::store_str( current_receiver(), N(storage), link_to_create.eospath, eospathlen, (char*)&link_to_create, len );
}
void apply_storage_rejectstore( char* eospath, uint32_t eospathlen ) {
char tmp[4098];
auto len = ::load_str( current_receiver(), current_receiver(), N(storage), eospath, eospathlen, tmp, 4098 );
TOKEN_NAME::link link_to_reject;
uint32_t ipfspathlen;
len = read_link_from_buffer( tmp, len, link_to_reject, eospathlen, ipfspathlen );
// eosio::require_auth( producer )
// How do we validate the require_auth() is a producer?
link_to_reject.accept = 0;
::store_str( current_receiver(), N(storage), link_to_reject.eospath, eospathlen, (char*)&link_to_reject, len );
}
} // namespace TOKEN_NAME
using namespace TOKEN_NAME;
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action ) {
if( code == N(storage) ) {
if( action == N(transfer) ) {
TOKEN_NAME::apply_storage_transfer( eosio::current_action< TOKEN_NAME::transfer >() );
} else if (action == N(setlink) ) {
TOKEN_NAME::apply_storage_setlink();
} else if (action == N(removelink) ) {
char tmp[1025];
auto len = read_action( tmp, 1025 );
TOKEN_NAME::apply_storage_removelink( tmp, len );
} else if (action == N(acceptstore) ) {
char tmp[1025];
auto len = read_action( tmp, 1025 );
TOKEN_NAME::apply_storage_createstore( tmp, len );
} else if (action == N(rejectstore) ) {
char tmp[1025];
auto len = read_action( tmp, 1025 );
TOKEN_NAME::apply_storage_rejectstore( tmp, len );
} else {
eosio_assert(0, "unknown message");
}
} else {
eosio_assert(0, "unknown code");
}
}
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/db.hpp>
/**
* @defgroup examplecontract Example Storage
* @brief Example Contract
* @ingroup contractapi
*
*/
/**
* Make it easy to change the account name the storage is deployed to.
*/
#ifndef TOKEN_NAME
#define TOKEN_NAME TOK
#endif
namespace TOKEN_NAME {
/**
* @defgroup storageapi Storage Contract
* @brief Defines the storage contract example
* @ingroup examplecontract
*
* @{
*/
/**
* Defines a storage token
*/
typedef eosio::token<uint64_t, N(storage)> storage_tokens;
/**
* transfer requires that the sender and receiver be the first two
* accounts notified and that the sender has provided authorization.
*/
struct transfer {
/**
* account to transfer from
*/
account_name from;
/**
* account to transfer to
*/
account_name to;
/**
* quantity to transfer
*/
storage_tokens quantity;
};
/**
* @brief row in account table stored within each scope
*/
struct PACKED(account) {
/**
Constructor with default zero quantity (balance).
*/
account( storage_tokens b = storage_tokens() ):balance(b),quotaused(0){}
/**
* The key is constant because there is only one record per scope/currency/accounts
*/
const uint64_t key = N(account);
/**
* Balance number of tokens in account
**/
storage_tokens balance;
/**
* Quota of storage Used
**/
uint64_t quotaused;
/**
Method to check if accoutn is empty.
@return true if account balance is zero and there is quota used.
**/
bool is_empty()const { return balance.quantity == 0 && quotaused == 0; }
};
/**
Assert statement to verify structure packing for account
**/
static_assert( sizeof(account) == sizeof(uint64_t)+sizeof(storage_tokens)+sizeof(uint64_t), "unexpected packing" );
/**
Defines the database table for account information
**/
using accounts = eosio::table<N(storage),N(storage),N(account),account,uint64_t>;
/**
* accounts information for owner is stored:
*
* owner/TOKEN_NAME/account/account -> account
*
* This API is made available for 3rd parties wanting read access to
* the users balance. If the account doesn't exist a default constructed
* account will be returned.
* @param owner The account owner
* @return account instance
*/
inline account get_account( account_name owner ) {
account owned_account;
accounts::get( owned_account, owner );
return owned_account;
}
/**
* This API is made available for 3rd parties wanting read access to
* the users quota of storage used. IF the account doesn't exist a default
* constructed account will be returned.
* @param owner The account owner
* @return uint64_t quota used
*/
inline uint64_t get_quota_used( account_name owner ) {
account owned_account;
accounts::get( owned_account, owner );
return owned_account.quotaused;
}
/**
Used to set a link to a file
**/
struct PACKED( link ) {
/**
* account owner
**/
account_name owner;
/**
* eos path
**/
char* eospath;
/**
* ipfs file path
**/
char* ipfspath;
/**
* size of file
**/
uint32_t size;
/**
* a flag that signals producers to cache file
**/
uint8_t store;
/**
* a flag that signals producers have accepted storage and cached file
**/
uint8_t accept;
/**
* tokens staked per file
**/
uint64_t stake;
/**
* name of producer who cached file
**/
account_name producer;
};
} /// @} /// storageapi
......@@ -145,7 +145,15 @@ extern "C" {
// test checktime
WASM_TEST_HANDLER(test_checktime, checktime_pass);
WASM_TEST_HANDLER(test_checktime, checktime_failure);
/*
// test softfloat
WASM_TEST_HANDLER(test_softfloat, test_f32_add);
WASM_TEST_HANDLER(test_softfloat, test_f32_sub);
WASM_TEST_HANDLER(test_softfloat, test_f32_mul);
WASM_TEST_HANDLER(test_softfloat, test_f32_div);
WASM_TEST_HANDLER(test_softfloat, test_f32_min);
*/
//unhandled test call
eosio_assert(false, "Unknown Test");
......
......@@ -125,7 +125,6 @@ struct test_db {
static void key_i128i128_general();
static void key_i64i64i64_general();
static void key_str_general();
static void key_str_table();
static void key_str_setup_limit();
......@@ -173,6 +172,22 @@ struct test_multi_index {
static void idx128_autoincrement_test_part2();
static void idx256_general();
static void idx_double_general();
static void idx64_pk_iterator_exceed_end();
static void idx64_sk_iterator_exceed_end();
static void idx64_pk_iterator_exceed_begin();
static void idx64_sk_iterator_exceed_begin();
static void idx64_pass_pk_ref_to_other_table();
static void idx64_pass_sk_ref_to_other_table();
static void idx64_pass_pk_end_itr_to_iterator_to();
static void idx64_pass_pk_end_itr_to_modify();
static void idx64_pass_pk_end_itr_to_erase();
static void idx64_pass_sk_end_itr_to_iterator_to();
static void idx64_pass_sk_end_itr_to_modify();
static void idx64_pass_sk_end_itr_to_erase();
static void idx64_modify_primary_key();
static void idx64_run_out_of_avl_pk();
static void idx64_sk_cache_pk_lookup();
static void idx64_pk_cache_sk_lookup();
};
struct test_crypto {
......@@ -275,3 +290,12 @@ struct test_checktime {
static void checktime_pass();
static void checktime_failure();
};
/*
struct test_softfloat {
static void test_f32_add();
static void test_f32_sub();
static void test_f32_mul();
static void test_f32_div();
static void test_f32_min();
};
*/
......@@ -3,26 +3,24 @@
#include "test_api.hpp"
using namespace eosio;
void test_real::create_instances() {
real lhs1(5);
eosio::real lhs1(5);
eosio_assert(lhs1.value() == 5, "real instance value is wrong");
}
void test_real::test_division() {
real lhs1(5);
real rhs1(10);
real result1 = lhs1 / rhs1;
eosio::real lhs1(5);
eosio::real rhs1(10);
eosio::real result1 = lhs1 / rhs1;
uint64_t a = double_div(i64_to_double(5), i64_to_double(10));
eosio_assert(a == result1.value(), "real division result is wrong");
}
void test_real::test_division_by_0() {
real lhs1(5);
real rhs1(0);
real result1 = lhs1 / rhs1;
eosio::real lhs1(5);
eosio::real rhs1(0);
eosio::real result1 = lhs1 / rhs1;
// in order to get rid of unused parameter warning
result1 = 0;
......@@ -30,27 +28,27 @@ void test_real::test_division_by_0() {
}
void test_real::test_multiplication() {
real lhs1(5);
real rhs1(10);
real result1 = lhs1 * rhs1;
eosio::real lhs1(5);
eosio::real rhs1(10);
eosio::real result1 = lhs1 * rhs1;
uint64_t res = double_mult( 5, 10 );
eosio_assert(res == result1.value(), "real multiplication result is wrong");
}
void test_real::test_addition()
{
real lhs1(5);
real rhs1(10);
real result1 = lhs1 / rhs1;
eosio::real lhs1(5);
eosio::real rhs1(10);
eosio::real result1 = lhs1 / rhs1;
uint64_t a = double_div(i64_to_double(5), i64_to_double(10));
real lhs2(5);
real rhs2(2);
real result2 = lhs2 / rhs2;
eosio::real lhs2(5);
eosio::real rhs2(2);
eosio::real result2 = lhs2 / rhs2;
uint64_t b = double_div(i64_to_double(5), i64_to_double(2));
real sum = result1+result2;
eosio::real sum = result1+result2;
uint64_t c = double_add( a, b );
eosio_assert(sum.value() == c, "real addition operation result is wrong");
}
......
......@@ -73,12 +73,14 @@ void copy_data(char* data, size_t data_len, eosio::vector<char>& data_out) {
}
void test_transaction::send_action() {
using namespace eosio;
test_dummy_action<N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal")> test_action = {DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C};
action act(eosio::vector<permission_level>{{N(testapi), N(active)}}, test_action);
act.send();
}
void test_transaction::send_action_empty() {
using namespace eosio;
test_action_action<N(testapi), WASM_TEST_ACTION("test_action", "assert_true")> test_action;
action act(eosio::vector<permission_level>{{N(testapi), N(active)}}, test_action);
......@@ -90,6 +92,7 @@ void test_transaction::send_action_empty() {
* cause failure due to a large action payload
*/
void test_transaction::send_action_large() {
using namespace eosio;
char large_message[8 * 1024];
test_action_action<N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal")> test_action;
copy_data(large_message, 8*1024, test_action.data);
......@@ -102,6 +105,7 @@ void test_transaction::send_action_large() {
* cause failure due recursive loop
*/
void test_transaction::send_action_recurse() {
using namespace eosio;
char buffer[1024];
read_action_data(buffer, 1024);
......@@ -116,6 +120,7 @@ void test_transaction::send_action_recurse() {
* cause failure due to inline TX failure
*/
void test_transaction::send_action_inline_fail() {
using namespace eosio;
test_action_action<N(testapi), WASM_TEST_ACTION("test_action", "assert_false")> test_action;
action act(vector<permission_level>{{N(testapi), N(active)}}, test_action);
......@@ -124,12 +129,14 @@ void test_transaction::send_action_inline_fail() {
}
void test_transaction::test_tapos_block_prefix() {
using namespace eosio;
int tbp;
read_action_data( (char*)&tbp, sizeof(int) );
eosio_assert( tbp == tapos_block_prefix(), "tapos_block_prefix does not match" );
}
void test_transaction::test_tapos_block_num() {
using namespace eosio;
int tbn;
read_action_data( (char*)&tbn, sizeof(int) );
eosio_assert( tbn == tapos_block_num(), "tapos_block_num does not match" );
......@@ -137,6 +144,7 @@ void test_transaction::test_tapos_block_num() {
void test_transaction::test_read_transaction() {
using namespace eosio;
checksum256 h;
transaction t;
char* p = (char*)&t;
......@@ -146,12 +154,14 @@ void test_transaction::test_read_transaction() {
}
void test_transaction::test_transaction_size() {
using namespace eosio;
uint32_t trans_size = 0;
read_action_data( (char*)&trans_size, sizeof(uint32_t) );
eosio_assert( trans_size == transaction_size(), "transaction size does not match" );
}
void test_transaction::send_transaction() {
using namespace eosio;
dummy_action payload = {DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C};
test_action_action<N(testapi), WASM_TEST_ACTION("test_action", "read_action_normal")> test_action;
......@@ -163,6 +173,7 @@ void test_transaction::send_transaction() {
}
void test_transaction::send_action_sender() {
using namespace eosio;
account_name cur_send;
read_action_data( &cur_send, sizeof(account_name) );
test_action_action<N(testapi), WASM_TEST_ACTION("test_action", "test_current_sender")> test_action;
......@@ -174,6 +185,7 @@ void test_transaction::send_action_sender() {
}
void test_transaction::send_transaction_empty() {
using namespace eosio;
auto trx = transaction();
trx.send(0);
......@@ -184,6 +196,7 @@ void test_transaction::send_transaction_empty() {
* cause failure due to a large transaction size
*/
void test_transaction::send_transaction_large() {
using namespace eosio;
auto trx = transaction();
for (int i = 0; i < 32; i ++) {
char large_message[1024];
......
......@@ -13,7 +13,7 @@ extern "C" {
}
void apply( unsigned long long code, unsigned long long action ) {
void apply( unsigned long long, unsigned long long action ) {
WASM_TEST_HANDLER(test_db, primary_i64_general);
WASM_TEST_HANDLER(test_db, primary_i64_lowerbound);
......@@ -22,8 +22,6 @@ extern "C" {
WASM_TEST_HANDLER(test_db, idx64_lowerbound);
WASM_TEST_HANDLER(test_db, idx64_upperbound);
WASM_TEST_HANDLER(test_db, key_str_general);
//unhandled test call
eosio_assert(false, "Unknown Test");
}
......
此差异已折叠。
......@@ -90,8 +90,7 @@ void test_extended_memory::test_page_memory_exceeded() {
}
void test_extended_memory::test_page_memory_negative_bytes() {
sbrk((uint32_t)-1);
eosio_assert(0, "Should have thrown exception for trying to remove memory");
eosio_assert(reinterpret_cast<int32_t>(sbrk(-1)) == -1, "Should have errored for trying to remove memory");
}
void test_extended_memory::test_initial_buffer() {
......
......@@ -3,7 +3,6 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/db.hpp>
/**
* @defgroup tictactoecontract Tic Tac Toe Contract
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册