提交 08267006 编写于 作者: D Daniel Larimer

manual merge much of identity and master

上级 57b8283b
......@@ -8,6 +8,8 @@
*.wasm
*.s
*.dot
*.abi.hpp
*.cmake
\#*
\.#*
CMakeCache.txt
......
......@@ -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)
......
add_subdirectory(eosio.system)
add_subdirectory(identity)
add_subdirectory(currency)
#add_subdirectory(bancor)
#add_subdirectory(eosio.system)
......
#pragma once
#include <eosiolib/print.hpp>
#include <eosiolib/action.hpp>
namespace eosio {
template<typename Contract, typename FirstAction>
......
#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 ) {
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, buf, sizeof(buf) );
store_i64( scope, TableName, 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;
};
}
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 );
}
}
......@@ -248,7 +248,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;
}
};
......@@ -261,7 +261,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;
}
};
......@@ -658,4 +658,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))
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册