通过以前的一些文章,我们知道Bitshares中operation都需要签名,也了解到签名一般都使用公私钥,看起来Bitshares签名有不少代码,到底都做了些什么呢?
对公私钥有兴趣的请google非对称加密、RSA、公私钥等
在operation函数最后,一般都会调用
return sign_transaction( tx, broadcast );
看看sign_transaction()函数:
signed_transaction sign_transaction(signed_transaction tx, bool broadcast = false)
{
set<public_key_type> pks = _remote_db->get_potential_signatures( tx );
flat_set<public_key_type> owned_keys;
owned_keys.reserve( pks.size() );
std::copy_if( pks.begin(), pks.end(), std::inserter(owned_keys, owned_keys.end()),
[this](const public_key_type& pk){ return _keys.find(pk) != _keys.end(); } );
set<public_key_type> approving_key_set = _remote_db->get_required_signatures( tx, owned_keys );
auto dyn_props = get_dynamic_global_properties();
tx.set_reference_block( dyn_props.head_block_id );
// first, some bookkeeping, expire old items from _recently_generated_transactions
// since transactions include the head block id, we just need the index for keeping transactions unique
// when there are multiple transactions in the same block. choose a time period that should be at
// least one block long, even in the worst case. 2 minutes ought to be plenty.
fc::time_point_sec oldest_transaction_ids_to_track(dyn_props.time - fc::minutes(2));
auto oldest_transaction_record_iter = _recently_generated_transactions.get<timestamp_index>().lower_bound(oldest_transaction_ids_to_track);
auto begin_iter = _recently_generated_transactions.get<timestamp_index>().begin();
_recently_generated_transactions.get<timestamp_index>().erase(begin_iter, oldest_transaction_record_iter);
uint32_t expiration_time_offset = 0;
for (;;)
{
tx.set_expiration( dyn_props.time + fc::seconds(30 + expiration_time_offset) );
tx.signatures.clear();
for( const public_key_type& key : approving_key_set )
tx.sign( get_private_key(key), _chain_id );
graphene::chain::transaction_id_type this_transaction_id = tx.id();
auto iter = _recently_generated_transactions.find(this_transaction_id);
if (iter == _recently_generated_transactions.end())
{
// we haven't generated this transaction before, the usual case
recently_generated_transaction_record this_transaction_record;
this_transaction_record.generation_time = dyn_props.time;
this_transaction_record.transaction_id = this_transaction_id;
_recently_generated_transactions.insert(this_transaction_record);
break;
}
// else we've generated a dupe, increment expiration time and re-sign it
++expiration_time_offset;
}
...
return tx;
}
看起来是通过 get_potential_signatures() 函数先取到可能的公钥,然后再通过 get_required_signatures() 取到需要签名的公钥,再填充交易块信息等签名后发送。
没明白怎么通过交易取到可能的签名公钥,继续看下这个函数:
set<public_key_type> database_api_impl::get_potential_signatures( const signed_transaction& trx )const
{
set<public_key_type> result;
trx.get_required_signatures(
_db.get_chain_id(),
flat_set<public_key_type>(),
[&]( account_id_type id )
{
const auto& auth = id(_db).active;
for( const auto& k : auth.get_keys() )
result.insert(k);
return &auth;
},
[&]( account_id_type id )
{
const auto& auth = id(_db).owner;
for( const auto& k : auth.get_keys() )
result.insert(k);
return &auth;
},
_db.get_global_properties().parameters.max_authority_depth
);
// Insert keys in required "other" authories
flat_set<account_id_type> required_active;
flat_set<account_id_type> required_owner;
vector<authority> other;
trx.get_required_authorities( required_active, required_owner, other );
for( const auto& auth : other )
for( const auto& key : auth.get_keys() )
result.insert( key );
return result;
}
函数内部又调用交易的 get_required_signatures() 函数:
set<public_key_type> signed_transaction::get_required_signatures(
const chain_id_type& chain_id,
const flat_set<public_key_type>& available_keys,
const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner,
uint32_t max_recursion_depth )const
{
flat_set<account_id_type> required_active;
flat_set<account_id_type> required_owner;
vector<authority> other;
get_required_authorities( required_active, required_owner, other );
flat_set<public_key_type> signature_keys = get_signature_keys( chain_id );
sign_state s( signature_keys, get_active, available_keys );
s.max_recursion = max_recursion_depth;
for( const auto& auth : other )
s.check_authority(&auth);
for( auto& owner : required_owner )
s.check_authority( get_owner( owner ) );
for( auto& active : required_active )
s.check_authority( active ) || s.check_authority( get_owner( active ) );
s.remove_unused_signatures();
set<public_key_type> result;
for( auto& provided_sig : s.provided_signatures )
if( available_keys.find( provided_sig.first ) != available_keys.end()
&& signature_keys.find( provided_sig.first ) == signature_keys.end() )
result.insert( provided_sig.first );
return result;
}
get_required_signatures函数有5个参数:链id、公钥set、get_active函数、get_owner函数、最大深度。
sign_state 用来存储签名状态,构造函数传入3个参数:已签名key、get_active函数、有效keys。这个函数后面一部分都是使用sign_state对象处理逻辑。
check_authority()函数可以判断出是否已有足够的key签名。
又会调用到 get_required_authorities() 函数,而此函数内部通过调用 operation_get_required_authorities() 得到需要的认证key。
void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const
{
for( const auto& op : operations )
operation_get_required_authorities( op, active, owner, other );
for( const auto& account : owner )
active.erase( account );
}
void operation_get_required_authorities( const operation& op,
flat_set<account_id_type>& active,
flat_set<account_id_type>& owner,
vector<authority>& other )
{
op.visit( operation_get_required_auth( active, owner, other ) );
}
当前交易所带的operations必须大于0个,怎么通过 operation_get_required_authorities() 取得需要的认证key?
operation_get_required_auth 是一个如下的类定义:
struct operation_get_required_auth
{
typedef void result_type;
flat_set<account_id_type>& active;
flat_set<account_id_type>& owner;
vector<authority>& other;
operation_get_required_auth( flat_set<account_id_type>& a,
flat_set<account_id_type>& own,
vector<authority>& oth ):active(a),owner(own),other(oth){}
template<typename T>
void operator()( const T& v )const
{
active.insert( v.fee_payer() );
v.get_required_active_authorities( active );
v.get_required_owner_authorities( owner );
v.get_required_authorities( other );
}
};
此处的v就是一个operation,active key会插入每个operation的fee_payer,这个fee_payer()函数是每个operation单独定义的。
从代码中看get_required_xxx也只有account_create_operation、account_update_operation、proposal_update_operation等少数几个operation有单独的处理,而缺省的operation并没有什么操作。那就是一般情况下,active key中会有操作的付费帐号。
account_update_operation,更新owner key时需要owner权限:
void get_required_owner_authorities( flat_set<account_id_type>& a )const
{ if( is_owner_update() ) a.insert( account ); }
void get_required_active_authorities( flat_set<account_id_type>& a )const
{ if( !is_owner_update() ) a.insert( account ); }
proposal_update_operation,需要提议审批人的权限:
void proposal_update_operation::get_required_active_authorities( flat_set<account_id_type>& a )const
{
for( const auto& i : active_approvals_to_add ) a.insert(i);
for( const auto& i : active_approvals_to_remove ) a.insert(i);
}
void proposal_update_operation::get_required_owner_authorities( flat_set<account_id_type>& a )const
{
for( const auto& i : owner_approvals_to_add ) a.insert(i);
for( const auto& i : owner_approvals_to_remove ) a.insert(i);
}
get_required_authorities在 get_required_authorities、transfer_from_blind_operation、blind_transfer_operation、proposal_update_operation有单独的处理,来看下proposal_update_operation这块认证权限的指定:
void proposal_update_operation::get_required_authorities( vector<authority>& o )const
{
authority auth;
for( const auto& k : key_approvals_to_add )
auth.key_auths[k] = 1;
for( const auto& k : key_approvals_to_remove )
auth.key_auths[k] = 1;
auth.weight_threshold = auth.key_auths.size();
o.emplace_back( std::move(auth) );
}
上面代码实现了提议的多重签名功能,weight_threshold指定了需要auth.key_auths指定的所有人同意提议。
交易签名比较简单,用私钥生成签名后加到signatures就完事了,如下:
const signature_type& graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)
{
digest_type h = sig_digest( chain_id );
signatures.push_back(key.sign_compact(h));
return signatures.back();
}
elliptic_impl_priv.cpp
compact_signature private_key::sign_compact( const fc::sha256& digest, bool require_canonical )const
{
FC_ASSERT( my->_key != empty_priv );
compact_signature result;
int recid;
unsigned int counter = 0;
do
{
FC_ASSERT( secp256k1_ecdsa_sign_compact( detail::_get_context(), (unsigned char*) digest.data(), (unsigned char*) result.begin() + 1, (unsigned char*) my->_key.data(), extended_nonce_function, &counter, &recid ));
} while( require_canonical && !public_key::is_canonical( result ) );
result.begin()[0] = 27 + 4 + recid;
return result;
}
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner,
uint32_t max_recursion_depth,
bool allow_committe,
const flat_set<account_id_type>& active_aprovals,
const flat_set<account_id_type>& owner_approvals )
{ try {
flat_set<account_id_type> required_active;
flat_set<account_id_type> required_owner;
vector<authority> other;
for( const auto& op : ops )
operation_get_required_authorities( op, required_active, required_owner, other );
if( !allow_committe )
GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
invalid_committee_approval, "Committee account may only propose transactions" );
sign_state s(sigs,get_active);
s.max_recursion = max_recursion_depth;
for( auto& id : active_aprovals )
s.approved_by.insert( id );
for( auto& id : owner_approvals )
s.approved_by.insert( id );
for( const auto& auth : other )
{
GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
}
// fetch all of the top level authorities
for( auto id : required_active )
{
GRAPHENE_ASSERT( s.check_authority(id) ||
s.check_authority(get_owner(id)),
tx_missing_active_auth, "Missing Active Authority ${id}", ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) );
}
for( auto id : required_owner )
{
GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() ||
s.check_authority(get_owner(id)),
tx_missing_owner_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) );
}
GRAPHENE_ASSERT(
!s.remove_unused_signatures(),
tx_irrelevant_sig,
"Unnecessary signature(s) detected"
);
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }
verify_authority函数中调用的其它函数在上面已经分析过了,就是判断需要哪些密钥签名和已经有哪些有效的签名。
这个函数在处理每笔交易时调用,如下:
processed_transaction database::_apply_transaction(const signed_transaction& trx)
{
...
if( !(skip & (skip_transaction_signatures | skip_authority_check) ) )
{
auto get_active = [&]( account_id_type id ) { return &id(*this).active; };
auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; };
trx.verify_authority( chain_id, get_active, get_owner, get_global_properties().parameters.max_authority_depth );
}
交易签名首先会需要operation指定的支付人的签名,对一些特殊的operation可能还需要其他帐户签名,如提议等。
简单过了一下权限签名相关的代码,下次再碰到“Missing Authority”提示时就容易了解和解决问题了。
感谢您阅读 @chaimyu 的帖子,期待您能留言交流!