diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index a0d88024..03710e99 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -70,18 +70,6 @@ void_result account_create_evaluator::do_evaluate( const account_create_operatio FC_ASSERT( current_account_itr == acnt_indx.indices().get().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().find( op.name.substr(0,pos) ); - FC_ASSERT( parent_account_itr != acnt_indx.indices().get().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) ) } diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index e31eead5..b7b2c3b2 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -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 diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index b893a0e4..749f2c7d 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -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 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 share_type; - typedef fc::sha224 secret_hash_type; - typedef uint16_t weight_type; + typedef fc::array 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 share_type; + typedef fc::sha224 secret_hash_type; + typedef uint16_t weight_type; /** * @brief An ID for some votable object diff --git a/libraries/chain/operations.cpp b/libraries/chain/operations.cpp index 598c7539..3b598cb3 100644 --- a/libraries/chain/operations.cpp +++ b/libraries/chain/operations.cpp @@ -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 ) diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 951e7695..2a67293d 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -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" ) ); } diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 26695bfa..3dca7e1d 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -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{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 {