parent
3ac8ccaa39
commit
f0ea015ccf
6 changed files with 113 additions and 117 deletions
|
|
@ -70,18 +70,6 @@ void_result account_create_evaluator::do_evaluate( const account_create_operatio
|
|||
FC_ASSERT( current_account_itr == acnt_indx.indices().get<by_name>().end() );
|
||||
}
|
||||
|
||||
// verify child account authority
|
||||
auto pos = op.name.find( '/' );
|
||||
if( pos != string::npos )
|
||||
{
|
||||
// TODO: lookup account by op.owner.auths[0] and verify the name
|
||||
// this should be a constant time lookup rather than log(N)
|
||||
auto parent_account_itr = acnt_indx.indices().get<by_name>().find( op.name.substr(0,pos) );
|
||||
FC_ASSERT( parent_account_itr != acnt_indx.indices().get<by_name>().end() );
|
||||
FC_ASSERT( verify_authority( *parent_account_itr, authority::owner ) );
|
||||
FC_ASSERT( op.owner.auths.find( parent_account_itr->id ) != op.owner.auths.end() );
|
||||
}
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@
|
|||
#define GRAPHENE_SYMBOL "CORE"
|
||||
#define GRAPHENE_ADDRESS_PREFIX "GPH"
|
||||
|
||||
#define GRAPHENE_MIN_SYMBOL_NAME_LENGTH 3
|
||||
#define GRAPHENE_MAX_SYMBOL_NAME_LENGTH 17
|
||||
#define GRAPHENE_MIN_ACCOUNT_NAME_LENGTH 1
|
||||
#define GRAPHENE_MAX_ACCOUNT_NAME_LENGTH 63
|
||||
|
||||
#define GRAPHENE_MIN_ASSET_SYMBOL_LENGTH 3
|
||||
#define GRAPHENE_MAX_ASSET_SYMBOL_LENGTH 16
|
||||
|
||||
#define GRAPHENE_MAX_ASSET_NAME_LENGTH 127
|
||||
|
||||
|
|
|
|||
|
|
@ -210,15 +210,15 @@ namespace graphene { namespace chain {
|
|||
account_transaction_history_object> account_transaction_history_id_type;
|
||||
typedef object_id< implementation_ids, impl_witness_schedule_object_type, witness_schedule_object > witness_schedule_id_type;
|
||||
|
||||
typedef fc::array<char,GRAPHENE_MAX_SYMBOL_NAME_LENGTH> symbol_type;
|
||||
typedef fc::ripemd160 block_id_type;
|
||||
typedef fc::ripemd160 checksum_type;
|
||||
typedef fc::ripemd160 transaction_id_type;
|
||||
typedef fc::sha256 digest_type;
|
||||
typedef fc::ecc::compact_signature signature_type;
|
||||
typedef safe<int64_t> share_type;
|
||||
typedef fc::sha224 secret_hash_type;
|
||||
typedef uint16_t weight_type;
|
||||
typedef fc::array<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> symbol_type;
|
||||
typedef fc::ripemd160 block_id_type;
|
||||
typedef fc::ripemd160 checksum_type;
|
||||
typedef fc::ripemd160 transaction_id_type;
|
||||
typedef fc::sha256 digest_type;
|
||||
typedef fc::ecc::compact_signature signature_type;
|
||||
typedef safe<int64_t> share_type;
|
||||
typedef fc::sha224 secret_hash_type;
|
||||
typedef uint16_t weight_type;
|
||||
|
||||
/**
|
||||
* @brief An ID for some votable object
|
||||
|
|
|
|||
|
|
@ -23,77 +23,99 @@
|
|||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* Valid symbols have at most a single "." that is not the first or last character.
|
||||
* Valid symbols can contain [A, Z], and '.'
|
||||
* They must start with [A, Z]
|
||||
* They must end with [A, Z]
|
||||
* They can contain a maximum of one '.'
|
||||
*/
|
||||
bool is_valid_symbol( const string& symbol )
|
||||
{
|
||||
if( symbol.size() < GRAPHENE_MIN_SYMBOL_NAME_LENGTH || symbol.size() > GRAPHENE_MAX_SYMBOL_NAME_LENGTH )
|
||||
if( symbol.size() < GRAPHENE_MIN_ASSET_SYMBOL_LENGTH )
|
||||
return false;
|
||||
|
||||
if( symbol.front() == '.' || symbol.back() == '.' )
|
||||
if( symbol.size() > GRAPHENE_MAX_ASSET_SYMBOL_LENGTH )
|
||||
return false;
|
||||
|
||||
if( !isalpha( symbol.front() ) )
|
||||
return false;
|
||||
|
||||
if( !isalpha( symbol.back() ) )
|
||||
return false;
|
||||
|
||||
bool dot_already_present = false;
|
||||
for( const auto c : symbol )
|
||||
{
|
||||
if( isalpha( c ) && isupper( c ) )
|
||||
continue;
|
||||
|
||||
if( c == '.' )
|
||||
{
|
||||
if( dot_already_present )
|
||||
return false;
|
||||
|
||||
dot_already_present = true;
|
||||
continue;
|
||||
}
|
||||
else if( !isalpha( c ) || !isupper( c ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid names are all lower case, start with [a-z] and may
|
||||
* have "." or "-" in the name along with a single '/'. The
|
||||
* next character after a "/", "." or "-" cannot be [0-9] or
|
||||
* another '.', '-'.
|
||||
*
|
||||
* Valid names can contain [a, z], [0, 9], '.', and '-'
|
||||
* They must start with [a, z]
|
||||
* They must end with [a, z] or [0, 9]
|
||||
* '.' must be followed by [a, z]
|
||||
* '-' must be followed by [a, z] or [0, 9]
|
||||
*/
|
||||
bool is_valid_name( const string& s )
|
||||
bool is_valid_name( const string& name )
|
||||
{
|
||||
if( s.size() < 2 ) return false;
|
||||
if( s.size() >= 64 ) return false;
|
||||
if( name.size() < GRAPHENE_MIN_ACCOUNT_NAME_LENGTH )
|
||||
return false;
|
||||
|
||||
int num_slash = 0;
|
||||
char prev = ' ';
|
||||
for( auto c : s )
|
||||
{
|
||||
if( c >= 'a' && c <= 'z' ){}
|
||||
else if( c >= '0' && c <= '9' )
|
||||
{
|
||||
if( prev == ' ' || prev == '.' || prev == '/' ) return false;
|
||||
}
|
||||
else switch( c )
|
||||
{
|
||||
case '/':
|
||||
if( ++num_slash > 1 ) return false;
|
||||
case '.':
|
||||
if( prev == '-' ) return false;
|
||||
case '-':
|
||||
if( prev == ' ' || prev == '/' || prev == '.' ) return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
prev = c;
|
||||
}
|
||||
switch( s.back() )
|
||||
{
|
||||
case '/': case '-': case '.':
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
if( name.size() > GRAPHENE_MAX_ACCOUNT_NAME_LENGTH )
|
||||
return false;
|
||||
|
||||
if( !isalpha( name.front() ) )
|
||||
return false;
|
||||
|
||||
if( !isalpha( name.back() ) && !isdigit( name.back() ) )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < name.size(); ++i )
|
||||
{
|
||||
const auto c = name.at( i );
|
||||
|
||||
if( isalpha( c ) && islower( c ) )
|
||||
continue;
|
||||
|
||||
if( isdigit( c ) )
|
||||
continue;
|
||||
|
||||
if( c == '.' )
|
||||
{
|
||||
const auto next = name.at( i + 1 );
|
||||
if( !isalpha( next ) )
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if( c == '-' )
|
||||
{
|
||||
const auto next = name.at( i + 1 );
|
||||
if( !isalpha( next ) && !isdigit( next ) )
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_cheap_name( const string& n )
|
||||
|
|
|
|||
|
|
@ -41,12 +41,38 @@ using namespace graphene::db;
|
|||
|
||||
BOOST_FIXTURE_TEST_SUITE( basic_tests, database_fixture )
|
||||
|
||||
/** verify that names are RFC-1035 compliant https://tools.ietf.org/html/rfc1035
|
||||
/**
|
||||
* Verify that names are RFC-1035 compliant https://tools.ietf.org/html/rfc1035
|
||||
* https://github.com/cryptonomex/graphene/issues/15
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE( valid_name_test )
|
||||
{
|
||||
BOOST_REQUIRE( is_valid_name( "a" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "A" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "0" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "." ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "-" ) );
|
||||
|
||||
BOOST_REQUIRE( is_valid_name( "aa" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aA" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "a0" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "a." ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "a-" ) );
|
||||
|
||||
BOOST_REQUIRE( is_valid_name( "aaa" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aAa" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "a0a" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "a.a" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "a-a" ) );
|
||||
|
||||
BOOST_REQUIRE( is_valid_name( "aa0" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aA0" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "a00" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "a.0" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "a-0" ) );
|
||||
|
||||
BOOST_REQUIRE( is_valid_name( "aaa-bbb-1" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aaa-bbb.1" ) );
|
||||
|
||||
BOOST_REQUIRE( !is_valid_name( "aaa,bbb-1" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aaa_bbb-1" ) );
|
||||
|
|
@ -65,11 +91,12 @@ BOOST_AUTO_TEST_CASE( valid_name_test )
|
|||
BOOST_REQUIRE( is_valid_name( "aaa.bbb-1" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aaa.bbb.1" ) );
|
||||
|
||||
BOOST_REQUIRE( is_valid_name( "aaa--bbb--1" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "xn--sandmnnchen-p8a.de" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "aaa--bbb--1" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "xn--sandmnnchen-p8a.de" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "xn-sandmnnchen-p8a.de" ) );
|
||||
|
||||
BOOST_REQUIRE( is_valid_name( "this-label-has-less-than-64-characters--63-to-be-really-precise" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "this-label-has-more-than-63-characters---64-to-be-really-precise" ) );
|
||||
BOOST_REQUIRE( is_valid_name( "this-label-has-less-than-64-char.acters-63-to-be-really-precise" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "this-label-has-more-than-63-char.act.ers-64-to-be-really-precise" ) );
|
||||
BOOST_REQUIRE( !is_valid_name( "none.of.these.labels.has.more.than-63.chars--but.still.not.valid" ) );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -363,50 +363,6 @@ BOOST_AUTO_TEST_CASE( create_account_test )
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( child_account )
|
||||
{
|
||||
try {
|
||||
INVOKE(create_account_test);
|
||||
fc::ecc::private_key child_private_key = fc::ecc::private_key::generate();
|
||||
fc::ecc::private_key nathan_private_key = fc::ecc::private_key::generate();
|
||||
const auto& child_key = register_key(child_private_key.get_public_key());
|
||||
const auto& nathan_key = register_key(nathan_private_key.get_public_key());
|
||||
const account_object& nathan = get_account("nathan");
|
||||
const account_object& root = create_account("root");
|
||||
upgrade_to_lifetime_member(root);
|
||||
|
||||
skip_key_index_test = true;
|
||||
db.modify(nathan, [nathan_key](account_object& a) {
|
||||
a.owner = authority(1, nathan_key.get_id(), 1);
|
||||
a.active = authority(1, nathan_key.get_id(), 1);
|
||||
});
|
||||
|
||||
BOOST_CHECK(nathan.active.get_keys() == vector<key_id_type>{nathan_key.get_id()});
|
||||
|
||||
auto op = make_account("nathan/child");
|
||||
op.registrar = root.id;
|
||||
op.owner = authority(1, child_key.get_id(), 1);
|
||||
op.active = authority(1, child_key.get_id(), 1);
|
||||
trx.operations.emplace_back(op);
|
||||
trx.sign(key_id_type(), delegate_priv_key);
|
||||
|
||||
BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception);
|
||||
sign(trx, nathan_key.id,nathan_private_key);
|
||||
BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception);
|
||||
trx.signatures.clear();
|
||||
op.owner = authority(1, account_id_type(nathan.id), 1);
|
||||
trx.operations = {op};
|
||||
trx.sign(key_id_type(), delegate_priv_key);
|
||||
trx.sign(nathan_key.id, nathan_private_key);
|
||||
db.push_transaction(trx);
|
||||
|
||||
BOOST_CHECK( get_account("nathan/child").active.auths == op.active.auths );
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( update_account )
|
||||
{
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in a new issue