diff --git a/Docker/Dockerfile b/Docker/Dockerfile index bbed7a6bf97..458e5ac2b8f 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu +FROM ubuntu:16.04 MAINTAINER xiaobo (peterwillcn@gmail.com) RUN echo 'APT::Install-Recommends 0;' >> /etc/apt/apt.conf.d/01norecommends \ diff --git a/contracts/eoslib/db.h b/contracts/eoslib/db.h index dae97dabdb5..d5ae2f9007d 100644 --- a/contracts/eoslib/db.h +++ b/contracts/eoslib/db.h @@ -82,6 +82,11 @@ extern "C" { */ int32_t store_i64( AccountName scope, TableName table, const void* data, uint32_t datalen ); +/** + * @return 1 if the record was updated, 0 if no record with key was found + */ +int32_t update_i64( AccountName scope, TableName table, const void* data, uint32_t datalen ); + /** * @param scope - the account scope that will be read, must exist in the transaction scopes list * @param code - identifies the code that controls write-access to the data @@ -94,11 +99,17 @@ int32_t store_i64( AccountName scope, TableName table, const void* data, uint32_ int32_t load_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); int32_t front_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); int32_t back_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); +int32_t next_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); +int32_t previous_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); +int32_t lower_bound_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); +int32_t upper_bound_i64( AccountName scope, AccountName code, TableName table, void* data, uint32_t datalen ); /** + * @param data - must point to at lest 8 bytes containing primary key + * * @return 1 if a record was removed, and 0 if no record with key was found */ -int32_t remove_i64( AccountName scope, TableName table, uint64_t key ); +int32_t remove_i64( AccountName scope, TableName table, void* data ); ///@} db_i64 @@ -145,34 +156,34 @@ int32_t previous_primary_i128i128( AccountName scope, AccountName code, TableNam int32_t load_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); -int32_t upper_bound_primary_i128i128( AccountName scope, AccountName code, TableName table, - const void* key, void* data, uint32_t len ); -int32_t lower_bound_primary_i128i128( AccountName scope, AccountName code, TableName table, - const void* key, void* data, uint32_t len ); +int32_t upper_bound_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); +int32_t lower_bound_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); int32_t front_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); int32_t back_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); int32_t next_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); int32_t previous_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); - -int32_t upper_bound_secondary_i128i128( AccountName scope, AccountName code, TableName table, - const void* key, void* data, uint32_t len ); -int32_t lower_bound_secondary_i128i128( AccountName scope, AccountName code, TableName table, - const void* key, void* data, uint32_t len ); +int32_t upper_bound_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); +int32_t lower_bound_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); int32_t load_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ); /** * @param data - must point to at lest 32 bytes containing {primary,secondary} * - * @return true if the record was removed, false if no record was found + * @return 1 if a record was removed, and 0 if no record with key was found */ -bool remove_i128i128( AccountName scope, TableName table, const void* data ); +int32_t remove_i128i128( AccountName scope, TableName table, const void* data ); +/** + * @return 1 if a new record was created, 0 if an existing record was updated + */ +int32_t store_i128i128( AccountName scope, TableName table, const void* data, uint32_t len ); + /** - * Creates or updates a record and returns true if successful + * @return 1 if the record was updated, 0 if no record with key was found */ -bool store_i128i128( AccountName scope, TableName table, const void* data, uint32_t len ); +int32_t update_i128i128( AccountName scope, TableName table, const void* data, uint32_t len ); ///@} dbi128i128 } diff --git a/contracts/eoslib/db.hpp b/contracts/eoslib/db.hpp index 916d96654a9..a66ca6f200b 100644 --- a/contracts/eoslib/db.hpp +++ b/contracts/eoslib/db.hpp @@ -56,19 +56,50 @@ struct table_impl { static int32_t load_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { return load_primary_i128i128( scope, code, table, data, len ); } - static int32_t front_secondary( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ) { - return front_secondary_i128i128( scope, code, table, data, len ); + static int32_t next_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return next_primary_i128i128( scope, code, table, data, len ); } - static int32_t back_secondary( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ) { - return back_secondary_i128i128( scope, code, table, data, len ); + static int32_t previous_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return previous_primary_i128i128( scope, code, table, data, len ); + } + static int32_t upper_bound_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return upper_bound_primary_i128i128( scope, code, table, data, len ); + } + static int32_t lower_bound_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return lower_bound_primary_i128i128( scope, code, table, data, len ); + } + + static int32_t front_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return front_secondary_i128i128( scope, code, table, data, len ); + } + static int32_t back_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return back_secondary_i128i128( scope, code, table, data, len ); + } + static int32_t load_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return load_secondary_i128i128( scope, code, table, data, len ); + } + static int32_t next_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return next_secondary_i128i128( scope, code, table, data, len ); + } + static int32_t previous_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return previous_secondary_i128i128( scope, code, table, data, len ); + } + static int32_t upper_bound_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return upper_bound_secondary_i128i128( scope, code, table, data, len ); + } + static int32_t lower_bound_secondary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return lower_bound_secondary_i128i128( scope, code, table, data, len ); } - static bool remove( uint64_t scope, uint64_t table, const void* data ) { + static int32_t remove( uint64_t scope, uint64_t table, const void* data ) { return remove_i128i128( scope, table, data ); } - static bool store( AccountName scope, TableName table, const void* data, uint32_t len ) { + static int32_t store( AccountName scope, TableName table, const void* data, uint32_t len ) { return store_i128i128( scope, table, data, len ); } + static int32_t update( AccountName scope, TableName table, const void* data, uint32_t len ) { + return update_i128i128( scope, table, data, len ); + } }; template<> @@ -79,15 +110,31 @@ struct table_impl { static int32_t back_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { return back_i64( scope, code, table, data, len ); } - static bool remove( uint64_t scope, uint64_t table, const void* data ) { - return remove_i64( scope, table, *((uint64_t*)data) ); - } static int32_t load_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { return load_i64( scope, code, table, data, len ); } - static bool store( AccountName scope, TableName table, const void* data, uint32_t len ) { + static int32_t next( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return next_i64( scope, code, table, data, len ); + } + static int32_t previous( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return previous_i64( scope, code, table, data, len ); + } + static int32_t lower_bound( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return lower_bound_i64( scope, code, table, data, len ); + } + static int32_t upper_bound( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) { + return upper_bound_i64( scope, code, table, data, len ); + } + + static int32_t remove( uint64_t scope, uint64_t table, const void* data ) { + return remove_i64( scope, table, (uint64_t*)data); + } + static int32_t store( AccountName scope, TableName table, const void* data, uint32_t len ) { return store_i64( scope, table, data, len ); } + static int32_t update( AccountName scope, TableName table, const void* data, uint32_t len ) { + return update_i64( scope, table, data, len ); + } }; @@ -142,7 +189,7 @@ struct Table { return impl::upper_bound_primary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record); } static bool remove( const Record& r, uint64_t s = scope ) { - return impl::remove( s, table, &r ); + return impl::remove( s, table, &r ) != 0; } }; @@ -169,7 +216,7 @@ struct Table { return impl::upper_bound_secondary( s, code, table, &p &r, sizeof(Record) ) == sizeof(Record); } static bool remove( const Record& r, uint64_t s = scope ) { - return impl::remove( s, table, &r ); + return impl::remove( s, table, &r ) != 0; } }; @@ -182,8 +229,12 @@ struct Table { assert( impl::store( s, table, &r, sizeof(r) ), "error storing record" ); return true; } + static bool update( const Record& r, uint64_t s = scope ) { + assert( impl::update( s, table, &r, sizeof(r) ), "error updating record" ); + return true; + } static bool remove( const Record& r, uint64_t s = scope ) { - return impl::remove( s, table, &r ); + return impl::remove( s, table, &r ) != 0; } }; @@ -232,7 +283,7 @@ struct Table { return impl::upper_bound_primary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record); } static bool remove( const Record& r ) { - return impl::remove( scope, table, &r ); + return impl::remove( scope, table, &r ) != 0; } }; @@ -249,11 +300,15 @@ struct Table { } static bool store( const Record& r, uint64_t s = scope ) { - return impl::store( s, table, &r, sizeof(r) ); + return impl::store( s, table, &r, sizeof(r) ) != 0; + } + + static bool update( const Record& r, uint64_t s = scope ) { + return impl::update( s, table, &r, sizeof(r) ) != 0; } static bool remove( const Record& r, uint64_t s = scope ) { - return impl::remove( s, table, &r ); + return impl::remove( s, table, &r ) != 0; } }; diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp index 404297bd25c..c6654322d92 100644 --- a/contracts/test_api/test_api.cpp +++ b/contracts/test_api/test_api.cpp @@ -46,6 +46,8 @@ extern "C" { WASM_TEST_HANDLER(test_db, key_i64_store_scope); WASM_TEST_HANDLER(test_db, key_i64_remove_scope); WASM_TEST_HANDLER(test_db, key_i64_not_found); + WASM_TEST_HANDLER(test_db, key_i64_front_back); + WASM_TEST_HANDLER(test_db, key_i128i128_general); //test crypto diff --git a/contracts/test_api/test_api.hpp b/contracts/test_api/test_api.hpp index ce38294ef59..6726a8badbb 100644 --- a/contracts/test_api/test_api.hpp +++ b/contracts/test_api/test_api.hpp @@ -84,6 +84,7 @@ struct test_db { static unsigned int key_i64_store_scope(); static unsigned int key_i64_remove_scope(); static unsigned int key_i64_not_found(); + static unsigned int key_i64_front_back(); static unsigned int key_i128i128_general(); }; diff --git a/contracts/test_api/test_db.cpp b/contracts/test_api/test_db.cpp index d6223dbb1fb..638f2c4a971 100644 --- a/contracts/test_api/test_db.cpp +++ b/contracts/test_api/test_db.cpp @@ -16,15 +16,19 @@ struct TestModelV2 : TestModel { uint64_t new_field; }; - struct OrderID { - AccountName name = 0; - uint64_t number = 0; - }; +struct TestModelV3 : TestModelV2 { + uint64_t another_field; +}; struct TestModel128x2 { - OrderID id; + uint128_t number; uint128_t price; uint64_t extra; + uint64_t table_name; +}; + +struct TestModel128x2_V2 : TestModel128x2 { + uint64_t new_field; }; #pragma pack(pop) @@ -55,7 +59,50 @@ unsigned int test_db::key_i64_general() { res = store_i64(currentCode(), N(test_table), &alice, sizeof(TestModel)); WASM_ASSERT(res != 0, "store alice" ); + + //fill with different ages in adjacent tables + dave.age=123; store_i64(currentCode(), N(test_tabld), &dave, sizeof(TestModel)); + dave.age=124; store_i64(currentCode(), N(test_tablf), &dave, sizeof(TestModel)); + carol.age=125; store_i64(currentCode(), N(test_tabld), &carol, sizeof(TestModel)); + carol.age=126; store_i64(currentCode(), N(test_tablf), &carol, sizeof(TestModel)); + bob.age=127; store_i64(currentCode(), N(test_tabld), &bob, sizeof(TestModel)); + bob.age=128; store_i64(currentCode(), N(test_tablf), &bob, sizeof(TestModel)); + alice.age=129; store_i64(currentCode(), N(test_tabld), &alice, sizeof(TestModel)); + alice.age=130; store_i64(currentCode(), N(test_tablf), &alice, sizeof(TestModel)); + + TestModel tmp; + + res = front_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "front_i64 1"); + my_memset(&tmp, 0, sizeof(TestModel)); + + res = back_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "front_i64 2"); + + res = previous_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol previous"); + res = previous_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob previous"); + + res = previous_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "alice previous"); + + res = previous_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "previous null"); + + res = next_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "bob next"); + + res = next_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "carol next"); + + res = next_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "dave next"); + + res = next_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "next null"); + my_memset(&alice, 0, sizeof(TestModel)); WASM_ASSERT(alice.name == 0 && alice.age == 0 && alice.phone == 0, "my_memset"); @@ -118,32 +165,127 @@ unsigned int test_db::key_i64_general() { res = load_i64(currentCode(), currentCode(), N(test_table), &alicev2, sizeof(TestModelV2)); WASM_ASSERT(res == sizeof(TestModelV2) && alicev2.age == 21 && alicev2.phone == 1234 && alicev2.new_field == 66655444, "alice model v2"); + my_memset(&tmp, 0, sizeof(TestModel)); + tmp.name = N(bob); + res = lower_bound_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(bob), "lower_bound_i64 bob" ); + + my_memset(&tmp, 0, sizeof(TestModel)); + tmp.name = N(boc); + res = lower_bound_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(carol), "lower_bound_i64 carol" ); + + my_memset(&tmp, 0, sizeof(TestModel)); + tmp.name = N(dave); + res = lower_bound_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(uint64_t) ); + WASM_ASSERT(res == sizeof(uint64_t) && tmp.name == N(dave), "lower_bound_i64 dave" ); + + my_memset(&tmp, 0, sizeof(TestModel)); + tmp.name = N(davf); + res = lower_bound_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(uint64_t) ); + WASM_ASSERT(res == -1, "lower_bound_i64 fail" ); + + my_memset(&tmp, 0, sizeof(TestModel)); + tmp.name = N(alice); + res = upper_bound_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.age == 15 && tmp.name == N(bob), "upper_bound_i64 bob" ); + + my_memset(&tmp, 0, sizeof(TestModel)); + tmp.name = N(dave); + res = upper_bound_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "upper_bound_i64 dave" ); + + TestModelV3 tmp2; + tmp2.name = N(alice); + + res = load_i64(currentCode(), currentCode(), N(test_table), &tmp2, sizeof(TestModelV3)); + WASM_ASSERT(res == sizeof(TestModelV2) && + tmp2.age == 21 && + tmp2.phone == 1234 && + tmp2.new_field == 66655444, + "load4update"); + + tmp2.another_field = 221122; + res = update_i64(currentCode(), N(test_table), &tmp2, sizeof(TestModelV3)); + WASM_ASSERT(res == 1, "update_i64"); + + res = load_i64(currentCode(), currentCode(), N(test_table), &tmp2, sizeof(TestModelV3)); + WASM_ASSERT(res == sizeof(TestModelV3) && + tmp2.age == 21 && + tmp2.phone == 1234 && + tmp2.new_field == 66655444 && + tmp2.another_field == 221122, + "load4update"); + + tmp2.age = 11; + res = update_i64(currentCode(), N(test_table), &tmp2, sizeof(uint64_t)+1 ); + WASM_ASSERT(res == 1, "update_i64 small"); + + res = load_i64(currentCode(), currentCode(), N(test_table), &tmp2, sizeof(TestModelV3)); + WASM_ASSERT(res == sizeof(TestModelV3) && + tmp2.age == 11 && + tmp2.phone == 1234 && + tmp2.new_field == 66655444 && + tmp2.another_field == 221122, + "load_i64 update_i64"); + + + //Remove dummy records + uint64_t tables[] { N(test_tabld), N(test_tablf) }; + for(auto& t : tables) { + while( front_i64( currentCode(), currentCode(), t, &tmp, sizeof(TestModel) ) != -1 ) { + remove_i64(currentCode(), t, &tmp); + } + } + return WASM_TEST_PASS; } unsigned int test_db::key_i64_remove_all() { uint32_t res = 0; + uint64_t key; - res = remove_i64(currentCode(), N(test_table), N(alice)); + key = N(alice); + res = remove_i64(currentCode(), N(test_table), &key); WASM_ASSERT(res == 1, "remove alice"); - res = remove_i64(currentCode(), N(test_table), N(bob)); + + key = N(bob); + res = remove_i64(currentCode(), N(test_table), &key); WASM_ASSERT(res == 1, "remove bob"); - res = remove_i64(currentCode(), N(test_table), N(carol)); + + key = N(carol); + res = remove_i64(currentCode(), N(test_table), &key); WASM_ASSERT(res == 1, "remove carol"); - res = remove_i64(currentCode(), N(test_table), N(dave)); + + key = N(dave); + res = remove_i64(currentCode(), N(test_table), &key); WASM_ASSERT(res == 1, "remove dave"); + TestModel tmp; + res = front_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "front_i64 remove"); - res = remove_i64(currentCode(), N(test_table), N(alice)); - WASM_ASSERT(res == 0, "remove alice 2"); - res = remove_i64(currentCode(), N(test_table), N(bob)); - WASM_ASSERT(res == 0, "remove bob 2"); - res = remove_i64(currentCode(), N(test_table), N(carol)); - WASM_ASSERT(res == 0, "remove carol 2"); - res = remove_i64(currentCode(), N(test_table), N(dave)); - WASM_ASSERT(res == 0, "remove dave 2"); + res = back_i64( currentCode(), currentCode(), N(test_table), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "back_i64_i64 remove"); + + key = N(alice); + res = remove_i64(currentCode(), N(test_table), &key); + WASM_ASSERT(res == 0, "remove alice 1"); + key = N(bob); + res = remove_i64(currentCode(), N(test_table), &key); + WASM_ASSERT(res == 0, "remove bob 1"); + + key = N(carol); + res = remove_i64(currentCode(), N(test_table), &key); + WASM_ASSERT(res == 0, "remove carol 1"); + + key = N(dave); + res = remove_i64(currentCode(), N(test_table), &key); + WASM_ASSERT(res == 0, "remove dave 1"); + + return WASM_TEST_PASS; } @@ -177,86 +319,164 @@ unsigned int test_db::key_i64_not_found() { auto res = load_i64(currentCode(), currentCode(), N(just_uint64), &dummy, sizeof(uint64_t)); WASM_ASSERT(res == -1, "i64_not_found load"); - res = remove_i64(currentCode(), N(just_uint64), dummy); + res = remove_i64(currentCode(), N(just_uint64), &dummy); WASM_ASSERT(res == 0, "i64_not_found remove"); return WASM_TEST_PASS; } -// extern "C" { -// unsigned int store_set_in_table(uint64_t table_name); -// }; +unsigned int test_db::key_i64_front_back() { + + uint32_t res = 0; + + TestModel dave { N(dave), 46, 6535354}; + TestModel carol{ N(carol), 30, 545342453}; + store_i64(currentCode(), N(b), &dave, sizeof(TestModel)); + store_i64(currentCode(), N(b), &carol, sizeof(TestModel)); + + TestModel bob { N(bob), 15, 11932435}; + TestModel alice{ N(alice), 20, 4234622}; + store_i64(currentCode(), N(a), &bob, sizeof(TestModel)); + store_i64(currentCode(), N(a), &alice, sizeof(TestModel)); + + TestModel tmp; + + my_memset(&tmp, 0, sizeof(TestModel)); + res = front_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 1"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = back_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 2"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = front_i64( currentCode(), currentCode(), N(b), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(carol) && tmp.age == 30 && tmp.phone == 545342453, "key_i64_front 3"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = back_i64( currentCode(), currentCode(), N(b), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 4"); + + uint64_t key = N(carol); + remove_i64(currentCode(), N(b), &key); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = front_i64( currentCode(), currentCode(), N(b), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 5"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = back_i64( currentCode(), currentCode(), N(b), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(dave) && tmp.age == 46 && tmp.phone == 6535354, "key_i64_front 6"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = front_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 7"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = back_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(bob) && tmp.age == 15 && tmp.phone == 11932435, "key_i64_front 8"); + + key = N(dave); + remove_i64(currentCode(), N(b), &key); + + res = front_i64( currentCode(), currentCode(), N(b), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "key_i64_front 9"); + res = back_i64( currentCode(), currentCode(), N(b), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "key_i64_front 10"); + + key = N(bob); + remove_i64(currentCode(), N(a), &key); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = front_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 11"); + + my_memset(&tmp, 0, sizeof(TestModel)); + res = back_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == sizeof(TestModel) && tmp.name == N(alice) && tmp.age == 20 && tmp.phone == 4234622, "key_i64_front 12"); + + key = N(alice); + remove_i64(currentCode(), N(a), &key); + + res = front_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "key_i64_front 13"); + res = back_i64( currentCode(), currentCode(), N(a), &tmp, sizeof(TestModel) ); + WASM_ASSERT(res == -1, "key_i64_front 14"); + + return WASM_TEST_PASS; +} unsigned int store_set_in_table(uint64_t table_name) { uint32_t res = 0; - TestModel128x2 alice0{{N(alice),0}, 500, N(alice0)}; - TestModel128x2 alice1{{N(alice),1}, 400, N(alice1)}; - TestModel128x2 alice2{{N(alice),2}, 300, N(alice2)}; + TestModel128x2 alice0{0, 500, N(alice0), table_name}; + TestModel128x2 alice1{1, 400, N(alice1), table_name}; + TestModel128x2 alice2{2, 300, N(alice2), table_name}; + TestModel128x2 alice22{2, 200, N(alice22), table_name}; res = store_i128i128(currentCode(), table_name, &alice0, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store alice0" ); + WASM_ASSERT(res == 1, "store alice0" ); res = store_i128i128(currentCode(), table_name, &alice1, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store alice1" ); + WASM_ASSERT(res == 1, "store alice1" ); res = store_i128i128(currentCode(), table_name, &alice2, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store alice2" ); + WASM_ASSERT(res == 1, "store alice2" ); + + res = store_i128i128(currentCode(), table_name, &alice22, sizeof(TestModel128x2)); + WASM_ASSERT(res == 1, "store alice22" ); - TestModel128x2 bob0{{N(bob), 0}, 1, N(bob0)}; - TestModel128x2 bob1{{N(bob), 1}, 2, N(bob1)}; - TestModel128x2 bob2{{N(bob), 2}, 3, N(bob2)}; - TestModel128x2 bob3{{N(bob), 3}, 4, N(bob3)}; + TestModel128x2 bob0{10, 1, N(bob0), table_name}; + TestModel128x2 bob1{11, 2, N(bob1), table_name}; + TestModel128x2 bob2{12, 3, N(bob2), table_name}; + TestModel128x2 bob3{13, 4, N(bob3), table_name}; res = store_i128i128(currentCode(), table_name, &bob0, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store bob0" ); + WASM_ASSERT(res == 1, "store bob0" ); res = store_i128i128(currentCode(), table_name, &bob1, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store bob1" ); + WASM_ASSERT(res == 1, "store bob1" ); res = store_i128i128(currentCode(), table_name, &bob2, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store bob2" ); + WASM_ASSERT(res == 1, "store bob2" ); res = store_i128i128(currentCode(), table_name, &bob3, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store bob3" ); + WASM_ASSERT(res == 1, "store bob3" ); - TestModel128x2 carol0{{N(carol), 0}, 900, N(carol0)}; - TestModel128x2 carol1{{N(carol), 1}, 800, N(carol1)}; - TestModel128x2 carol2{{N(carol), 2}, 700, N(carol2)}; - TestModel128x2 carol3{{N(carol), 3}, 600, N(carol3)}; + TestModel128x2 carol0{20, 900, N(carol0), table_name}; + TestModel128x2 carol1{21, 800, N(carol1), table_name}; + TestModel128x2 carol2{22, 700, N(carol2), table_name}; + TestModel128x2 carol3{23, 600, N(carol3), table_name}; res = store_i128i128(currentCode(), table_name, &carol0, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store carol0" ); + WASM_ASSERT(res == 1, "store carol0" ); res = store_i128i128(currentCode(), table_name, &carol1, sizeof(TestModel128x2)); - eos::print("Store carol1 ", res, "\n"); - WASM_ASSERT(res > 0, "store carol1" ); - eos::print("Store carol1 ", res, " ", carol1.id.name, " ", carol1.id.number, " ", carol1.price, " ", carol1.extra, "\n"); - + WASM_ASSERT(res == 1, "store carol1" ); res = store_i128i128(currentCode(), table_name, &carol2, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store carol2" ); + WASM_ASSERT(res == 1, "store carol2" ); res = store_i128i128(currentCode(), table_name, &carol3, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store carol3" ); + WASM_ASSERT(res == 1, "store carol3" ); - TestModel128x2 dave0{{N(dave) ,0}, 8, N(dave0)}; - TestModel128x2 dave1{{N(dave) ,1}, 7, N(dave1)}; - TestModel128x2 dave2{{N(dave) ,2}, 5, N(dave2)}; - TestModel128x2 dave3{{N(dave) ,3}, 4, N(dave3)}; + TestModel128x2 dave0{30, 8, N(dave0), table_name}; + TestModel128x2 dave1{31, 7, N(dave1), table_name}; + TestModel128x2 dave2{32, 5, N(dave2), table_name}; + TestModel128x2 dave3{33, 4, N(dave3), table_name}; res = store_i128i128(currentCode(), table_name, &dave0, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store dave0" ); + WASM_ASSERT(res == 1, "store dave0" ); res = store_i128i128(currentCode(), table_name, &dave1, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store dave1" ); + WASM_ASSERT(res == 1, "store dave1" ); res = store_i128i128(currentCode(), table_name, &dave2, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store dave2" ); + WASM_ASSERT(res == 1, "store dave2" ); res = store_i128i128(currentCode(), table_name, &dave3, sizeof(TestModel128x2)); - WASM_ASSERT(res > 0, "store dave3" ); + WASM_ASSERT(res == 1, "store dave3" ); return WASM_TEST_PASS; } @@ -265,42 +485,184 @@ unsigned int test_db::key_i128i128_general() { uint32_t res = 0; - if(store_set_in_table(N(table1)) != WASM_TEST_PASS) + if(store_set_in_table(N(table0)) != WASM_TEST_PASS) return WASM_TEST_FAIL; - // if(store_set_in_table(N(table2)) != WASM_TEST_PASS) - // return WASM_TEST_FAIL; + if(store_set_in_table(N(table1)) != WASM_TEST_PASS) + return WASM_TEST_FAIL; - // if(store_set_in_table(N(table3)) != WASM_TEST_PASS) - // return WASM_TEST_FAIL; + if(store_set_in_table(N(table2)) != WASM_TEST_PASS) + return WASM_TEST_FAIL; TestModel128x2 tmp; my_memset(&tmp, 0, sizeof(TestModel128x2)); - tmp.id.name = N(carol); - tmp.id.number = 1; - tmp.price = 800; + tmp.number = 21; res = load_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); WASM_ASSERT( res == sizeof(TestModel128x2) && - tmp.id.name == N(carol) && - tmp.id.number == 1 && tmp.price == 800 && - tmp.extra == N(carol1), + tmp.extra == N(carol1) && + tmp.table_name == N(table1), "carol1 primary load"); my_memset(&tmp, 0, sizeof(TestModel128x2)); - tmp.price = 4; //TestModel128x2 dave3{{N(dave) ,3}, 4, N(dave3)}; - //TestModel128x2 bob3{{N(bob), 3}, 4, N(bob3)}; + tmp.price = 4; res = load_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); - //eos::print("SECOND -> ", res, " ", tmp.id.name, " ", tmp.id.number, " ", tmp.price, " ", tmp.extra, "\n"); WASM_ASSERT( res == sizeof(TestModel128x2) && - tmp.id.name == N(bob) && - tmp.id.number == 3 && + tmp.number == 13 && tmp.price == 4 && - tmp.extra == N(bob3), + tmp.extra == N(bob3) && + tmp.table_name == N(table1), "bob3 secondary load"); + + res = front_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 0 && + tmp.price == 500 && + tmp.extra == N(alice0) && + tmp.table_name == N(table1), + "front primary load"); + res = previous_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT(res == -1, "previous primary fail"); + + res = next_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 1 && + tmp.price == 400 && + tmp.extra == N(alice1) && + tmp.table_name == N(table1), + "next primary ok"); + + res = front_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 10 && + tmp.price == 1 && + tmp.extra == N(bob0) && + tmp.table_name == N(table1), + "front secondary ok"); + + res = previous_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT(res == -1, "previous secondary fail"); + + res = next_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 11 && + tmp.price == 2 && + tmp.extra == N(bob1) && + tmp.table_name == N(table1), + "next secondary ok"); + + res = back_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 33 && + tmp.price == 4 && + tmp.extra == N(dave3) && + tmp.table_name == N(table1), + "back primary ok"); + + res = next_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT(res == -1, "next primary fail"); + + res = previous_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 32 && + tmp.price == 5 && + tmp.extra == N(dave2) && + tmp.table_name == N(table1), + "previous primary ok"); + + res = back_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 20 && + tmp.price == 900 && + tmp.extra == N(carol0) && + tmp.table_name == N(table1), + "back secondary ok"); + + res = next_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT(res == -1, "next secondary fail"); + + res = previous_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 21 && + tmp.price == 800 && + tmp.extra == N(carol1) && + tmp.table_name == N(table1), + "previous secondary ok"); + + tmp.number = 1; + + res = lower_bound_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 1 && + tmp.price == 400 && + tmp.extra == N(alice1) && + tmp.table_name == N(table1), + "lb primary ok"); + + res = upper_bound_primary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 2 && + tmp.price == 200 && + tmp.extra == N(alice22) && + tmp.table_name == N(table1), + "ub primary ok"); + + tmp.price = 800; + + res = lower_bound_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp, sizeof(TestModel128x2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp.number == 21 && + tmp.price == 800 && + tmp.extra == N(carol1) && + tmp.table_name == N(table1), + "lb secondary ok"); + + TestModel128x2_V2 tmp2; + tmp2.price = 800; + + res = upper_bound_secondary_i128i128( currentCode(), currentCode(), N(table1), &tmp2, sizeof(TestModel128x2_V2) ); + WASM_ASSERT( res == sizeof(TestModel128x2) && + tmp2.number == 20 && + tmp2.price == 900 && + tmp2.extra == N(carol0) && + tmp2.table_name == N(table1), + "ub secondary ok"); + + tmp2.new_field = 123456; + res = update_i128i128(currentCode(), N(table1), &tmp2, sizeof(TestModel128x2_V2)); + WASM_ASSERT( res == 1, "update_i128i128 ok"); + + my_memset(&tmp2, 0, sizeof(TestModel128x2_V2)); + tmp2.number = 20; + + res = load_primary_i128i128(currentCode(), currentCode(), N(table1), &tmp2, sizeof(TestModel128x2_V2)); + WASM_ASSERT( res == sizeof(TestModel128x2_V2) && + tmp2.number == 20 && + tmp2.price == 900 && + tmp2.extra == N(carol0) && + tmp2.table_name == N(table1) && + tmp2.new_field == 123456, + "lp update_i128i128 ok"); + + tmp2.extra = N(xxxxx); + res = update_i128i128(currentCode(), N(table1), &tmp2, sizeof(uint128_t)*2+sizeof(uint64_t)); + WASM_ASSERT( res == 1, "update_i128i128 small ok"); + + res = load_primary_i128i128(currentCode(), currentCode(), N(table1), &tmp2, sizeof(TestModel128x2_V2)); + WASM_ASSERT( res == sizeof(TestModel128x2_V2) && + tmp2.number == 20 && + tmp2.price == 900 && + tmp2.extra == N(xxxxx) && + tmp2.table_name == N(table1) && + tmp2.new_field == 123456, + "lp small update_i128i128 ok"); + return WASM_TEST_PASS; } + + //eos::print("xxxx ", res, " ", tmp2.name, " ", uint64_t(tmp2.age), " ", tmp2.phone, " ", tmp2.new_field, "\n"); \ No newline at end of file diff --git a/libraries/chain/include/eos/chain/key_value_object.hpp b/libraries/chain/include/eos/chain/key_value_object.hpp index b3670f2f25f..d0e1c891a80 100644 --- a/libraries/chain/include/eos/chain/key_value_object.hpp +++ b/libraries/chain/include/eos/chain/key_value_object.hpp @@ -91,7 +91,8 @@ namespace eos { namespace chain { member, member, member - > + >, + composite_key_compare< std::less,std::less,std::less,std::less,std::less > > > >; diff --git a/libraries/chain/include/eos/chain/message_handling_contexts.hpp b/libraries/chain/include/eos/chain/message_handling_contexts.hpp index dd38d31208f..239094d5354 100644 --- a/libraries/chain/include/eos/chain/message_handling_contexts.hpp +++ b/libraries/chain/include/eos/chain/message_handling_contexts.hpp @@ -20,30 +20,107 @@ class apply_context { : controller(con), db(db), trx(t), msg(m), code(code), mutable_controller(con), mutable_db(db), used_authorizations(msg.authorization.size(), false){} - int32_t store_i64( Name scope, Name table, Name key, const char* data, uint32_t len); - int32_t remove_i64( Name scope, Name table, Name key ); - int32_t remove_i128i128( Name scope, Name table, uint128_t primary, uint128_t secondary ); - int32_t store_i128i128( Name scope, Name table, uint128_t primary, uint128_t secondary, - const char* data, uint32_t len ); + int32_t store_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t len); - int32_t load_i64( Name scope, Name code, Name table, Name Key, char* data, uint32_t maxlen ); + int32_t update_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t len); + + int32_t remove_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t len); + + int32_t load_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + int32_t front_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + int32_t back_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + int32_t next_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + int32_t previous_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + int32_t lower_bound_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + int32_t upper_bound_i64( Name scope, Name code, Name table, uint64_t *key, char* data, uint32_t maxlen ); + + + int32_t store_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, + char* data, uint32_t len ); + + int32_t update_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, + char* data, uint32_t len ); + + int32_t remove_i128i128( Name scope, Name code, Name table, uint128_t *primary, uint128_t *secondary, + char* data, uint32_t len ); + + template + int32_t load_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ); + + template + int32_t front_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ); + + template + int32_t back_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ); + + template + int32_t next_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ); + + template + int32_t previous_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ); + + template + int32_t lower_bound_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ); + + template + int32_t upper_bound_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ); + + + int32_t load_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); int32_t front_primary_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + int32_t back_primary_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + int32_t next_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + int32_t previous_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + int32_t lower_bound_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + int32_t upper_bound_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + + int32_t load_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + int32_t front_secondary_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + int32_t back_secondary_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); - int32_t load_primary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); - int32_t load_secondary_i128i128( Name scope, Name code, Name table, + + int32_t next_secondary_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); - int32_t lowerbound_primary_i128i128( Name scope, Name code, Name table, + + int32_t previous_secondary_i128i128( Name scope, Name code, Name table, uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); - int32_t lowerbound_secondary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + int32_t lower_bound_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); + + int32_t upper_bound_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* data, uint32_t maxlen ); /** * @brief Require @ref account to have approved of this message diff --git a/libraries/chain/include/eos/chain/wasm_interface.hpp b/libraries/chain/include/eos/chain/wasm_interface.hpp index e63dc438645..5bed357e671 100644 --- a/libraries/chain/include/eos/chain/wasm_interface.hpp +++ b/libraries/chain/include/eos/chain/wasm_interface.hpp @@ -8,8 +8,6 @@ namespace eos { namespace chain { class chain_controller; -typedef int32_t (apply_context::*load_i128i128_fnc)(Name, Name, Name, uint128_t* , uint128_t*, char* , uint32_t); - /** * @class wasm_interface * @@ -64,7 +62,11 @@ class wasm_interface { wasm_interface(); - int32_t load_i128i128_object( uint64_t scope, uint64_t code, uint64_t table, int32_t valueptr, int32_t valuelen, load_i128i128_fnc function ); + template + int32_t validate_i128i128(int32_t valueptr, int32_t valuelen, Function&& func); + + template + int32_t validate_i64(int32_t valueptr, int32_t valuelen, Function&& func); }; diff --git a/libraries/chain/message_handling_contexts.cpp b/libraries/chain/message_handling_contexts.cpp index 69004ef718a..a2fc326c463 100644 --- a/libraries/chain/message_handling_contexts.cpp +++ b/libraries/chain/message_handling_contexts.cpp @@ -44,14 +44,18 @@ bool apply_context::all_authorizations_used() const { return boost::algorithm::all_of_equal(used_authorizations, true); } -int32_t apply_context::load_i64( Name scope, Name code, Name table, Name key, char* value, uint32_t valuelen ) { +// +// i64 functions +// + +int32_t apply_context::load_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { require_scope( scope ); const auto* obj = db.find( boost::make_tuple( - AccountName(scope), - AccountName(code), - AccountName(table), - AccountName(key) ) ); + AccountName(scope), + AccountName(code), + AccountName(table), + AccountName(*key) ) ); if( obj == nullptr ) { return -1; } auto copylen = std::min(obj->value.size(),valuelen); if( copylen ) { @@ -60,125 +64,314 @@ int32_t apply_context::load_i64( Name scope, Name code, Name table, Name key, ch return copylen; } -int32_t apply_context::back_primary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { +int32_t apply_context::remove_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); - return -1; - /* - require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), - uint64_t(code), - table.value+1, - *primary, uint128_t(0) ) ); + const auto* obj = db.find( boost::make_tuple( + AccountName(scope), + AccountName(code), + AccountName(table), + AccountName(*key) ) ); + if( obj ) { + mutable_db.remove( *obj ); + return 1; + } + return 0; +} - if( itr == idx.begin() && itr == idx.end() ) - return 0; +int32_t apply_context::store_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); - --itr; + const auto* obj = db.find( boost::make_tuple( + AccountName(scope), + AccountName(code), + AccountName(table), + AccountName(*key) ) ); + if( obj ) { + mutable_db.modify( *obj, [&]( auto& o ) { + o.value.assign(value, valuelen); + }); + return 0; + } else { + mutable_db.create( [&](auto& o) { + o.scope = scope; + o.code = code; + o.table = table; + o.key = *key; + o.value.insert( 0, value, valuelen ); + }); + return 1; + } +} - if( itr->scope != scope || - itr->code != code || - itr->table != table || - itr->primary_key != *primary ) return -1; +int32_t apply_context::update_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); - *secondary = itr->secondary_key; - *primary = itr->primary_key; - - auto copylen = std::min(itr->value.size(),valuelen); - if( copylen ) { - itr->value.copy(value, copylen); - } - return copylen; - */ + const auto* obj = db.find( boost::make_tuple( + AccountName(scope), + AccountName(code), + AccountName(table), + AccountName(*key) ) ); + if( !obj ) return 0; + + mutable_db.modify( *obj, [&]( auto& o ) { + if( valuelen > o.value.size() ) { + o.value.resize(valuelen); + } + memcpy(o.value.data(), value, valuelen); + }); + + return 1; } -int32_t apply_context::back_secondary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { +int32_t apply_context::front_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); - require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( AccountName(scope), - AccountName(code), - table.value+1, - *secondary, uint128_t(0) ) ); + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( scope, code, table, uint64_t(0) ) ); - if( itr == idx.end() ) - return -1; + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table) return -1; - --itr; + *key = itr->key; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; +} - if( itr->scope != scope || - itr->code != code || - itr->table != table - ) return -2; +int32_t apply_context::back_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); - *secondary = itr->secondary_key; - *primary = itr->primary_key; - - auto copylen = std::min(itr->value.size(),valuelen); - if( copylen ) { - itr->value.copy(value, copylen); - } - return copylen; + const auto& idx = db.get_index(); + auto itr = idx.upper_bound( boost::make_tuple( scope, code, table, uint64_t(-1) ) ); + + if( std::distance(idx.begin(), itr) == 0 ) return -1; + + --itr; + + if( itr->scope != scope || + itr->code != code || + itr->table != table) return -1; + + *key = itr->key; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; } +int32_t apply_context::next_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); -int32_t apply_context::front_primary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( scope, code, table, *key ) ); + + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table || + uint64_t(itr->key) != *key ) return -1; + + ++itr; + + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table ) return -1; + + *key = itr->key; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; +} + +int32_t apply_context::previous_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); - require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), - uint64_t(code), - uint64_t(table), - *primary, uint128_t(0) ) ); + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( scope, code, table, *key ) ); - if( itr == idx.end() ) - return -1; + if( itr == idx.end() || + itr == idx.begin() || + itr->scope != scope || + itr->code != code || + itr->table != table || + uint64_t(itr->key) != *key ) return -1; - --itr; + --itr; - if( itr->scope != scope || - itr->code != code || - itr->table != table - ) return -2; + if( itr->scope != scope || + itr->code != code || + itr->table != table ) return -1; + *key = itr->key; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; +} + +int32_t apply_context::lower_bound_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); + + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( scope, code, table, *key ) ); + + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table) return -1; + + *key = itr->key; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; +} + +int32_t apply_context::upper_bound_i64( Name scope, Name code, Name table, uint64_t *key, char* value, uint32_t valuelen ) { + require_scope( scope ); + + const auto& idx = db.get_index(); + auto itr = idx.upper_bound( boost::make_tuple( scope, code, table, *key ) ); + + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table) return -1; + + *key = itr->key; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; +} + +// +// i128i128 helper functions +// + +template +struct i128i128_Key { + static const uint128_t& get_first(const key128x128_value_object& obj) { + return obj.primary_key; + } + static const uint128_t& get_second(const key128x128_value_object& obj) { + return obj.secondary_key; + } + static const uint128_t* get_first(uint128_t* primary, uint128_t* secondary) { + return primary; + } + static const uint128_t* get_second(uint128_t* primary, uint128_t* secondary) { + return secondary; + } +}; + +template <> +struct i128i128_Key { + static const uint128_t& get_first(const key128x128_value_object& obj) { + return obj.secondary_key; + } + static const uint128_t& get_second(const key128x128_value_object& obj) { + return obj.primary_key; + } + static const uint128_t* get_first(uint128_t* primary, uint128_t* secondary) { + return secondary; + } + static const uint128_t* get_second(uint128_t* primary, uint128_t* secondary) { + return primary; + } +}; + +// +// i128i128 generic functions +// + +template +int32_t apply_context::back_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ) { + require_scope( scope ); + + const auto& idx = db.get_index(); + auto itr = idx.upper_bound( boost::make_tuple( AccountName(scope), + AccountName(code), + table, + uint128_t(-1), uint128_t(-1) ) ); + + if( std::distance(idx.begin(), itr) == 0 ) return -1; + + --itr; + + if( itr->scope != scope || + itr->code != code || + itr->table != table ) return -1; + + *primary = itr->primary_key; *secondary = itr->secondary_key; - *primary = itr->primary_key; - + auto copylen = std::min(itr->value.size(),valuelen); if( copylen ) { itr->value.copy(value, copylen); } return copylen; } -int32_t apply_context::front_secondary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { - require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( AccountName(scope), - AccountName(code), - AccountName(table), +template +int32_t apply_context::front_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ) { + require_scope( scope ); + + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), + uint64_t(code), + uint64_t(table), uint128_t(0), uint128_t(0) ) ); + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table ) return -1; - FC_ASSERT( itr == idx.begin(), "lower bound of all 0 should be begin" ); + *primary = itr->primary_key; + *secondary = itr->secondary_key; - if( itr == idx.end() ) { - return -1; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); } + return copylen; +} + +template +int32_t apply_context::load_i128i128( Name scope, Name code, Name table, uint128_t* primary, + uint128_t* secondary, char* value, uint32_t valuelen ) { + require_scope( scope ); + auto key = i128i128_Key::get_first(primary, secondary); - if( itr->scope != scope || - itr->code != code || - itr->table != table ) { - return -2; - } + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), + uint64_t(code), + uint64_t(table), + *key, uint128_t(0) ) ); + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table || + i128i128_Key::get_first(*itr) != *key) return -1; + *primary = itr->primary_key; *secondary = itr->secondary_key; - *primary = itr->primary_key; - + auto copylen = std::min(itr->value.size(),valuelen); if( copylen ) { itr->value.copy(value, copylen); @@ -186,25 +379,36 @@ int32_t apply_context::front_secondary_i128i128( Name scope, Name code, Name tab return copylen; } +template +int32_t apply_context::next_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + require_scope( scope ); -int32_t apply_context::load_primary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + auto key1 = i128i128_Key::get_first(primary, secondary); + auto key2 = i128i128_Key::get_second(primary, secondary); - require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), - uint64_t(code), - uint64_t(table), - *primary, uint128_t(0) ) ); + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), + uint64_t(code), + uint64_t(table), + *key1, *key2 ) ); + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table || + i128i128_Key::get_first(*itr) != *key1 || + i128i128_Key::get_second(*itr) != *key2 ) return -1; - if( itr == idx.end() || - itr->scope != (scope) || - itr->code != (code) || - itr->table != (table) || - itr->primary_key != *primary ) return -1; + ++itr; + if( itr == idx.end() || + itr->scope != scope || + itr->code != code || + itr->table != table ) return -1; + + *primary = itr->primary_key; *secondary = itr->secondary_key; - + auto copylen = std::min(itr->value.size(),valuelen); if( copylen ) { itr->value.copy(value, copylen); @@ -212,24 +416,36 @@ int32_t apply_context::load_primary_i128i128( Name scope, Name code, Name table, return copylen; } -int32_t apply_context::load_secondary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { +template +int32_t apply_context::previous_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + require_scope( scope ); + + auto key1 = i128i128_Key::get_first(primary, secondary); + auto key2 = i128i128_Key::get_second(primary, secondary); + + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), + uint64_t(code), + uint64_t(table), + *key1, *key2 ) ); + if( itr == idx.end() || + itr == idx.begin() || + itr->scope != scope || + itr->code != code || + itr->table != table || + i128i128_Key::get_first(*itr) != *key1 || + i128i128_Key::get_second(*itr) != *key2 ) return -1; + + --itr; + + if( itr->scope != scope || + itr->code != code || + itr->table != table ) return -1; + + *primary = itr->primary_key; + *secondary = itr->secondary_key; - require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), - uint64_t(code), - uint64_t(table), - *secondary, uint128_t(0) ) ); - - if( itr == idx.end() || - itr->scope != (scope) || - itr->code != (code) || - itr->table != (table) || - itr->secondary_key != *secondary ) return -1; - - *primary = itr->primary_key; - auto copylen = std::min(itr->value.size(),valuelen); if( copylen ) { itr->value.copy(value, copylen); @@ -237,64 +453,69 @@ int32_t apply_context::load_secondary_i128i128( Name scope, Name code, Name tabl return copylen; } -int32_t apply_context::lowerbound_primary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { - +template +int32_t apply_context::lower_bound_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), - uint64_t(code), - uint64_t(table), - *primary, uint128_t(0) ) ); + auto key = i128i128_Key::get_first(primary, secondary); + + const auto& idx = db.get_index(); + auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), + uint64_t(code), + uint64_t(table), + *key, uint128_t(0) ) ); if( itr == idx.end() || itr->scope != scope || - itr->code != code || - itr->table != table ) return -1; + itr->code != code || + itr->table != table) return -1; - *primary = itr->primary_key; - *secondary = itr->secondary_key; + *primary = itr->primary_key; + *secondary = itr->secondary_key; - auto copylen = std::min(itr->value.size(),valuelen); - if( copylen ) { - itr->value.copy(value, copylen); - } - return copylen; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; } -int32_t apply_context::lowerbound_secondary_i128i128( Name scope, Name code, Name table, - uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { +template +int32_t apply_context::upper_bound_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { require_scope( scope ); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( uint64_t(scope), - uint64_t(code), - uint64_t(table), - uint128_t(0), *secondary ) ); + auto key = i128i128_Key::get_first(primary, secondary); + + const auto& idx = db.get_index(); + auto itr = idx.upper_bound( boost::make_tuple( uint64_t(scope), + uint64_t(code), + uint64_t(table), + *key, (unsigned __int128)(-1) ) ); if( itr == idx.end() || itr->scope != scope || - itr->code != code || + itr->code != code || itr->table != table ) return -1; - *primary = itr->primary_key; - *secondary = itr->secondary_key; + *primary = itr->primary_key; + *secondary = itr->secondary_key; - auto copylen = std::min(itr->value.size(),valuelen); - if( copylen ) { - itr->value.copy(value, copylen); - } - return copylen; + auto copylen = std::min(itr->value.size(),valuelen); + if( copylen ) { + itr->value.copy(value, copylen); + } + return copylen; } -int32_t apply_context::remove_i128i128( Name scope, Name table, uint128_t primary, uint128_t secondary ) { +int32_t apply_context::remove_i128i128( Name scope, Name code, Name table, uint128_t *primary, uint128_t *secondary, char* value, uint32_t valuelen ) { require_scope( scope ); const auto* obj = db.find( boost::make_tuple( - AccountName(scope), - AccountName(code), - AccountName(table), - primary, secondary) ); + AccountName(scope), + AccountName(code), + AccountName(table), + *primary, *secondary) ); if( obj ) { mutable_db.remove( *obj ); return 1; @@ -302,73 +523,134 @@ int32_t apply_context::remove_i128i128( Name scope, Name table, uint128_t primar return 0; } -int32_t apply_context::remove_i64( Name scope, Name table, Name key ) { +int32_t apply_context::store_i128i128( Name scope, Name code, Name table, uint128_t *primary, uint128_t *secondary, + char* value, uint32_t valuelen ) { require_scope( scope ); - - const auto* obj = db.find( boost::make_tuple( - AccountName(scope), - AccountName(code), - AccountName(table), - AccountName(key) ) ); - if( obj ) { - mutable_db.remove( *obj ); - return 1; - } - return 0; -} - -int32_t apply_context::store_i64( Name scope, Name table, Name key, const char* value, uint32_t valuelen ) { - require_scope( scope ); - - const auto* obj = db.find( boost::make_tuple( - AccountName(scope), - AccountName(code), - AccountName(table), - AccountName(key) ) ); + const auto* obj = db.find( boost::make_tuple( + AccountName(scope), + AccountName(code), + AccountName(table), + *primary, *secondary ) ); + //idump(( *((fc::uint128_t*)primary)) ); + //idump(( *((fc::uint128_t*)secondary)) ); if( obj ) { + wlog( "modify" ); mutable_db.modify( *obj, [&]( auto& o ) { o.value.assign(value, valuelen); }); return 0; } else { - mutable_db.create( [&](auto& o) { + wlog( "new" ); + mutable_db.create( [&](auto& o) { o.scope = scope; o.code = code; o.table = table; - o.key = key; + o.primary_key = *primary; + o.secondary_key = *secondary; o.value.insert( 0, value, valuelen ); }); - return valuelen; + return 1; } } -int32_t apply_context::store_i128i128( Name scope, Name table, uint128_t primary, uint128_t secondary, - const char* value, uint32_t valuelen ) { +int32_t apply_context::update_i128i128( Name scope, Name code, Name table, uint128_t *primary, uint128_t *secondary, + char* value, uint32_t valuelen ) { + require_scope( scope ); const auto* obj = db.find( boost::make_tuple( - AccountName(scope), - AccountName(code), - AccountName(table), - primary, secondary ) ); - idump(( *((fc::uint128_t*)&primary)) ); - idump(( *((fc::uint128_t*)&secondary)) ); - if( obj ) { - wlog( "modify" ); - mutable_db.modify( *obj, [&]( auto& o ) { - o.value.assign(value, valuelen); - }); + AccountName(scope), + AccountName(code), + AccountName(table), + *primary, *secondary ) ); + if( !obj ) { return 0; - } else { - wlog( "new" ); - mutable_db.create( [&](auto& o) { - o.scope = scope; - o.code = code; - o.table = table; - o.primary_key = primary; - o.secondary_key = secondary; - o.value.insert( 0, value, valuelen ); - }); - return valuelen; } + + mutable_db.modify( *obj, [&]( auto& o ) { + if( valuelen > o.value.size() ) { + o.value.resize(valuelen); + } + memcpy(o.value.data(), value, valuelen); + }); + + return 1; +} + +// +// i128i128 primary functions +// + +int32_t apply_context::load_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return load_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::front_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return front_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::back_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return back_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::next_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return next_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::previous_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return previous_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::lower_bound_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return lower_bound_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::upper_bound_primary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return upper_bound_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +// +// i128i128 secondary functions +// + +int32_t apply_context::front_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return front_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::load_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return load_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::back_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return back_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::next_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return next_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::previous_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return previous_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::lower_bound_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return load_i128i128(scope, code, table, primary, secondary, value, valuelen); +} + +int32_t apply_context::upper_bound_secondary_i128i128( Name scope, Name code, Name table, + uint128_t* primary, uint128_t* secondary, char* value, uint32_t valuelen ) { + return upper_bound_i128i128(scope, code, table, primary, secondary, value, valuelen); } } } // namespace eos::chain diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a2ef40212bb..70a395bbb82 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -33,15 +33,15 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) { throw checktime_exceeded(); } } - - int32_t load_i128i128_object( uint64_t scope, uint64_t code, uint64_t table, int32_t valueptr, int32_t valuelen, load_i128i128_fnc function ) { + template + int32_t validate_i128i128(int32_t valueptr, int32_t valuelen, Function&& func) { static const uint32_t keylen = 2*sizeof(uint128_t); FC_ASSERT( valuelen >= keylen, "insufficient data passed" ); auto& wasm = wasm_interface::get(); - FC_ASSERT( wasm.current_validate_context, "no validate context found" ); + FC_ASSERT( wasm.current_apply_context, "no apply context found" ); char* value = memoryArrayPtr( wasm.current_memory, valueptr, valuelen ); uint128_t* primary = reinterpret_cast(value); @@ -50,14 +50,54 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) { valuelen -= keylen; value += keylen; - auto res = (wasm.current_validate_context->*function)( - Name(scope), Name(code), Name(table), - primary, secondary, value, valuelen - ); + return func(wasm.current_apply_context, primary, secondary, value, valuelen); + } + + template + int32_t validate_i64(int32_t valueptr, int32_t valuelen, Function&& func) { + + static const uint32_t keylen = sizeof(uint64_t); + + FC_ASSERT( valuelen >= keylen ); + + auto& wasm = wasm_interface::get(); + FC_ASSERT( wasm.current_apply_context, "no apply context found" ); + + auto mem = wasm.current_memory; + char* value = memoryArrayPtr( mem, valueptr, valuelen); + uint64_t* key = reinterpret_cast(value); - if(res > 0) res += keylen; - return res; + valuelen -= keylen; + value += keylen; + + return func(wasm.current_apply_context, key, value, valuelen); } + +#define READ_i64_OBJ(func_name) \ + validate_i64(valueptr, valuelen, [&](apply_context* ctx, uint64_t* key, char *data, uint32_t datalen) -> int32_t { \ + auto res = ctx->func_name( Name(scope), Name(code), Name(table), key, data, datalen); \ + if (res >= 0) res += sizeof(uint64_t); \ + return res; \ + }); + +#define UPDATE_i64_OBJ(func_name, data_size) \ + validate_i64(valueptr, data_size, [&](apply_context* ctx, uint64_t* key, char *data, uint32_t datalen) -> int32_t { \ + return ctx->func_name( Name(scope), Name(ctx->code.value), Name(table), key, data, datalen); \ + }); + +#define READ_i128i128_OBJ(func_name) \ + validate_i128i128(valueptr, valuelen, [&](apply_context* ctx, uint128_t* primary, uint128_t* secondary, char *data, uint32_t datalen) -> int32_t { \ + auto res = ctx->func_name( Name(scope), Name(code), Name(table), primary, secondary, data, datalen); \ + if (res >= 0) res += 2*sizeof(uint128_t); \ + return res; \ + }); + +#define UPDATE_i128i128_OBJ(func_name, data_size) \ + validate_i128i128(valueptr, data_size, [&](apply_context* ctx, uint128_t* primary, uint128_t* secondary, char *data, uint32_t datalen) -> int32_t { \ + return ctx->func_name( Name(scope), Name(ctx->code.value), Name(table), primary, secondary, data, datalen); \ + }); + + DEFINE_INTRINSIC_FUNCTION3(env, assert_sha256,assert_sha256,none,i32,dataptr,i32,datalen,i32,hash) { FC_ASSERT( datalen > 0 ); @@ -104,25 +144,44 @@ DEFINE_INTRINSIC_FUNCTION0(env,now,now,i32) { return wasm_interface::get().current_validate_context->controller.head_block_time().sec_since_epoch(); } -DEFINE_INTRINSIC_FUNCTION4(env,store_i128i128,store_i128i128,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { - - static const uint32_t keylen = 2*sizeof(uint128_t); - - FC_ASSERT( valuelen >= keylen, "insufficient data passed" ); +DEFINE_INTRINSIC_FUNCTION4(env,store_i64,store_i64,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { + return UPDATE_i64_OBJ(store_i64, valuelen); +} - auto& wasm = wasm_interface::get(); - FC_ASSERT( wasm.current_apply_context, "no apply context found" ); +DEFINE_INTRINSIC_FUNCTION4(env,update_i64,update_i64,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { + return UPDATE_i64_OBJ(update_i64, valuelen); +} + +DEFINE_INTRINSIC_FUNCTION3(env,remove_i64,remove_i64,i32,i64,scope,i64,table,i32,valueptr) { + return UPDATE_i64_OBJ(remove_i64, sizeof(uint64_t)); +} + +DEFINE_INTRINSIC_FUNCTION5(env,load_i64,load_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(load_i64); +} - char* value = memoryArrayPtr( wasm.current_memory, valueptr, valuelen ); - uint128_t* primary = reinterpret_cast(value); - uint128_t* secondary = primary + 1; - - valuelen -= keylen; - value += keylen; +DEFINE_INTRINSIC_FUNCTION5(env,front_i64,front_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(front_i64); +} + +DEFINE_INTRINSIC_FUNCTION5(env,back_i64,back_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(back_i64); +} + +DEFINE_INTRINSIC_FUNCTION5(env,next_i64,next_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(next_i64); +} - //wdump((datalen)(valuelen)(result)); - return wasm.current_apply_context->store_i128i128( Name(scope), Name(table), - *primary, *secondary, value, valuelen ); +DEFINE_INTRINSIC_FUNCTION5(env,previous_i64,previous_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(previous_i64); +} + +DEFINE_INTRINSIC_FUNCTION5(env,lower_bound_i64,lower_bound_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(lower_bound_i64); +} + +DEFINE_INTRINSIC_FUNCTION5(env,upper_bound_i64,upper_bound_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i64_OBJ(upper_bound_i64); } struct i128_keys { @@ -130,102 +189,89 @@ struct i128_keys { uint128_t secondary; }; -DEFINE_INTRINSIC_FUNCTION3(env,remove_i128i128,remove_i128i128,i32,i64,scope,i64,table,i32,data) { - auto& wasm = wasm_interface::get(); - FC_ASSERT( wasm.current_apply_context, "not a valid apply context" ); - - const i128_keys& keys = memoryRef( wasm.current_memory, data ); - return wasm_interface::get().current_apply_context->remove_i128i128( Name(scope), Name(table), keys.primary, keys.secondary ); +DEFINE_INTRINSIC_FUNCTION4(env,store_i128i128,store_i128i128,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { + return UPDATE_i128i128_OBJ(store_i128i128, valuelen); } -DEFINE_INTRINSIC_FUNCTION5(env,load_primary_i128i128,load_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { - return load_i128i128_object(scope, code, table, valueptr, valuelen, &apply_context::load_primary_i128i128); +DEFINE_INTRINSIC_FUNCTION4(env,update_i128i128,update_i128i128,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { + return UPDATE_i128i128_OBJ(update_i128i128, valuelen); } -DEFINE_INTRINSIC_FUNCTION5(env,load_secondary_i128i128,load_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { - return load_i128i128_object(scope, code, table, valueptr, valuelen, &apply_context::load_secondary_i128i128); +DEFINE_INTRINSIC_FUNCTION3(env,remove_i128i128,remove_i128i128,i32,i64,scope,i64,table,i32,valueptr) { + return UPDATE_i128i128_OBJ(remove_i128i128, 2*sizeof(uint128_t)); } -DEFINE_INTRINSIC_FUNCTION5(env,back_primary_i128i128,back_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { - return load_i128i128_object(scope, code, table, valueptr, valuelen, &apply_context::back_primary_i128i128); +DEFINE_INTRINSIC_FUNCTION5(env,load_primary_i128i128,load_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(load_primary_i128i128); } DEFINE_INTRINSIC_FUNCTION5(env,front_primary_i128i128,front_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { - return load_i128i128_object(scope, code, table, valueptr, valuelen, &apply_context::front_primary_i128i128); + return READ_i128i128_OBJ(front_primary_i128i128); } -DEFINE_INTRINSIC_FUNCTION5(env,back_secondary_i128i128,back_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { - return load_i128i128_object(scope, code, table, valueptr, valuelen, &apply_context::back_secondary_i128i128); +DEFINE_INTRINSIC_FUNCTION5(env,back_primary_i128i128,back_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(back_primary_i128i128); } -DEFINE_INTRINSIC_FUNCTION5(env,front_secondary_i128i128,front_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { - return load_i128i128_object(scope, code, table, valueptr, valuelen, &apply_context::front_secondary_i128i128); +DEFINE_INTRINSIC_FUNCTION5(env,next_primary_i128i128,next_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(next_primary_i128i128); } -DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) { - auto& wasm = wasm_interface::get(); - return wasm.current_validate_context->code.value; +DEFINE_INTRINSIC_FUNCTION5(env,previous_primary_i128i128,previous_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(previous_primary_i128i128); } -DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) { - wasm_interface::get().current_validate_context->require_authorization( Name(account) ); +DEFINE_INTRINSIC_FUNCTION5(env,upper_bound_primary_i128i128,upper_bound_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(upper_bound_primary_i128i128); } -DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) { - wasm_interface::get().current_apply_context->require_recipient( account ); +DEFINE_INTRINSIC_FUNCTION5(env,lower_bound_primary_i128i128,lower_bound_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(lower_bound_primary_i128i128); } -DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) { - wasm_interface::get().current_validate_context->require_scope( scope ); +DEFINE_INTRINSIC_FUNCTION5(env,load_secondary_i128i128,load_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(load_secondary_i128i128); } -DEFINE_INTRINSIC_FUNCTION4(env,store_i64,store_i64,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) -{ - static const uint32_t keylen = sizeof(uint64_t); - - FC_ASSERT( valuelen >= sizeof(uint64_t) ); - - auto& wasm = wasm_interface::get(); - FC_ASSERT( wasm.current_apply_context, "no apply context found" ); +DEFINE_INTRINSIC_FUNCTION5(env,back_secondary_i128i128,back_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(back_secondary_i128i128); +} - auto mem = wasm.current_memory; - char* value = memoryArrayPtr( mem, valueptr, valuelen); - uint64_t* key = reinterpret_cast(value); +DEFINE_INTRINSIC_FUNCTION5(env,front_secondary_i128i128,front_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(front_secondary_i128i128); +} - valuelen -= keylen; - value += keylen; +DEFINE_INTRINSIC_FUNCTION5(env,next_secondary_i128i128,next_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(next_secondary_i128i128); +} - //idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) ); +DEFINE_INTRINSIC_FUNCTION5(env,previous_secondary_i128i128,previous_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(previous_secondary_i128i128); +} - return wasm.current_apply_context->store_i64( scope, table, *key, value, valuelen ); +DEFINE_INTRINSIC_FUNCTION5(env,upper_bound_secondary_i128i128,upper_bound_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(upper_bound_secondary_i128i128); } -DEFINE_INTRINSIC_FUNCTION5(env,load_i64,load_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) -{ - //idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) ); - static const uint32_t keylen = sizeof(uint64_t); - - FC_ASSERT( valuelen >= keylen ); +DEFINE_INTRINSIC_FUNCTION5(env,lower_bound_secondary_i128i128,lower_bound_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { + return READ_i128i128_OBJ(lower_bound_secondary_i128i128); +} +DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) { auto& wasm = wasm_interface::get(); - FC_ASSERT( wasm.current_validate_context, "no validate context found" ); - - auto mem = wasm.current_memory; - char* value = memoryArrayPtr( mem, valueptr, valuelen); - uint64_t* key = reinterpret_cast(value); + return wasm.current_validate_context->code.value; +} - valuelen -= keylen; - value += keylen; +DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) { + wasm_interface::get().current_validate_context->require_authorization( Name(account) ); +} - auto res = wasm.current_validate_context->load_i64( scope, code, table, *key, value, valuelen ); - if(res > 0) res += keylen; - return res; +DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) { + wasm_interface::get().current_apply_context->require_recipient( account ); } -DEFINE_INTRINSIC_FUNCTION3(env,remove_i64,remove_i64,i32,i64,scope,i64,table,i64,key) { - auto& wasm = wasm_interface::get(); - FC_ASSERT( wasm.current_apply_context, "no apply context found" ); - return wasm.current_apply_context->remove_i64( scope, table, key ); +DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) { + wasm_interface::get().current_validate_context->require_scope( scope ); } DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) { diff --git a/libraries/types/AbiSerializer.cpp b/libraries/types/AbiSerializer.cpp index 09de9db8e60..eb32d321c50 100644 --- a/libraries/types/AbiSerializer.cpp +++ b/libraries/types/AbiSerializer.cpp @@ -4,6 +4,10 @@ namespace eos { namespace types { + using boost::algorithm::ends_with; + using std::vector; + using std::string; + template inline fc::variant variantFromStream(fc::datastream& stream) { T temp; @@ -11,180 +15,94 @@ namespace eos { namespace types { return fc::variant(temp); } - AbiSerializer::AbiSerializer( const Abi& abi ) { - configureTypes(); - setAbi(abi); - } - - void AbiSerializer::configureTypes() { - - native_types.emplace("UInt8", std::make_pair( []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("UInt16", std::make_pair( []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("UInt32", std::make_pair( []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("UInt64", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("UInt128", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("UInt256", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("Int8", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("Int16", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("Int32", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("Int64", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - // native_types.emplace("Int128", std::make_pair( - // []( auto& stream ) -> auto { - // return variantFromStream<__int128>(stream); - // }, - // []( const fc::variant& var, fc::datastream& ds ){ - // fc::raw::pack( ds, var.as<__int128>() ); - // } - // )); - - // native_types.emplace("Int256", std::make_pair( - // []( auto& stream ) -> auto { - // return variantFromStream(stream); - // }, - // []( const fc::variant& var, fc::datastream& ds ){ - // fc::raw::pack( ds, var.as() ); - // } - // )); - - native_types.emplace("Name", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream(stream); - }, - []( const fc::variant& var, fc::datastream& ds ){ - fc::raw::pack( ds, var.as() ); - } - )); - - native_types.emplace("Time", std::make_pair( - []( auto& stream ) -> auto { - return variantFromStream