Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions imports/cdt.imports.in
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ get_block_num
get_blockchain_parameters_packed
get_code_hash
get_context_free_data
get_permission_lower_bound
get_ram_usage
get_resource_limits
get_sender
Expand Down
3 changes: 3 additions & 0 deletions libraries/native/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ extern "C" {
int64_t get_account_creation_time( capi_name account ) {
return intrinsics::get().call<intrinsics::get_account_creation_time>(account);
}
int32_t get_permission_lower_bound( capi_name account, capi_name permission, char* buffer, uint32_t buffer_size ) {
return intrinsics::get().call<intrinsics::get_permission_lower_bound>(account, permission, buffer, buffer_size);
}
uint64_t current_time() {
return intrinsics::get().call<intrinsics::current_time>();
}
Expand Down
1 change: 1 addition & 0 deletions libraries/native/native/sysio/intrinsics_def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ intrinsic_macro(ripemd160) \
intrinsic_macro(check_transaction_authorization) \
intrinsic_macro(check_permission_authorization) \
intrinsic_macro(get_account_creation_time) \
intrinsic_macro(get_permission_lower_bound) \
intrinsic_macro(current_time) \
intrinsic_macro(publication_time) \
intrinsic_macro(read_action_data) \
Expand Down
13 changes: 13 additions & 0 deletions libraries/sysiolib/capi/sysio/permission.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ check_permission_authorization( capi_name account,
__attribute__((sysio_wasm_import))
int64_t get_account_creation_time( capi_name account );

/**
* Look up the permission of an account with the smallest name >= the given permission name.
*
* @param account - the account to search
* @param permission - the lower bound permission name
* @param buffer - output buffer for serialized permission_record
* @param buffer_size - size of the output buffer
*
* @return -1 if no permission found, or the size of the serialized data
*/
__attribute__((sysio_wasm_import))
int32_t get_permission_lower_bound( capi_name account, capi_name permission, char* buffer, uint32_t buffer_size );

#ifdef __cplusplus
}
#endif
Expand Down
78 changes: 78 additions & 0 deletions libraries/sysiolib/contracts/sysio/permission.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
#include "../../core/sysio/name.hpp"
#include "../../core/sysio/time.hpp"

#include <cstring>
#include <optional>
#include <set>
#include <limits>
#include <vector>

namespace sysio {
namespace internal_use_do_not_use {
Expand All @@ -26,6 +29,9 @@ namespace sysio {
uint64_t);
__attribute__((sysio_wasm_import))
int64_t get_account_creation_time(uint64_t);

__attribute__((sysio_wasm_import))
int32_t get_permission_lower_bound(uint64_t account, uint64_t permission, char* buffer, uint32_t buffer_size);
}
}

Expand Down Expand Up @@ -185,4 +191,76 @@ namespace sysio {
internal_use_do_not_use::get_account_creation_time(account.value)));

}

/**
* @defgroup permission_types Permission Types
* @ingroup permission
* @brief Types for deserializing permission data from the get_permission_lower_bound intrinsic.
* @{
*/

struct perm_key_weight {
public_key key;
uint16_t weight;

SYSLIB_SERIALIZE( perm_key_weight, (key)(weight) )
};

struct perm_level_weight {
permission_level permission;
uint16_t weight;

SYSLIB_SERIALIZE( perm_level_weight, (permission)(weight) )
};

struct perm_authority {
uint32_t threshold = 0;
std::vector<perm_key_weight> keys;
std::vector<perm_level_weight> accounts;

SYSLIB_SERIALIZE( perm_authority, (threshold)(keys)(accounts) )
};

struct permission_record {
name perm_name;
name parent;
time_point last_updated;
perm_authority auth;

SYSLIB_SERIALIZE( permission_record, (perm_name)(parent)(last_updated)(auth) )
};

/// @}

/**
* Reads the permission record for the given account and exact permission name.
* Uses the get_permission_lower_bound intrinsic and checks for an exact match.
*
* @ingroup permission
*
* @param account - the account to search
* @param permission - the exact permission name to look up
*
* @return the permission_record if found, std::nullopt otherwise
*/
inline std::optional<permission_record> get_permission( name account, name permission ) {
// First call with small buffer to get size and check the returned permission name
char name_buf[8];
int32_t sz = internal_use_do_not_use::get_permission_lower_bound(
account.value, permission.value, name_buf, sizeof(name_buf) );

if( sz < 0 ) return std::nullopt;

// The first 8 bytes of the serialized data is the permission name
name returned_name;
std::memcpy( &returned_name, name_buf, sizeof(returned_name) );
if( returned_name != permission ) return std::nullopt;

// Second call with full buffer
std::vector<char> buf( static_cast<size_t>(sz) );
internal_use_do_not_use::get_permission_lower_bound(
account.value, permission.value, buf.data(), buf.size() );

return unpack<permission_record>( buf );
}
}
2 changes: 2 additions & 0 deletions tests/unit/test_contracts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/capi/capi_tests.abi ${CMAKE_CURRENT_

target_link_libraries(old_malloc_tests PUBLIC --use-freeing-malloc)

add_contract(permission_tests permission_tests permission_tests.cpp)

# Protobuf test contract
add_library(pb_protos INTERFACE)
target_add_protobuf(pb_protos OUTPUT_DIRECTORY test FILES test.proto)
Expand Down
73 changes: 73 additions & 0 deletions tests/unit/test_contracts/permission_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <sysio/sysio.hpp>
#include <sysio/permission.hpp>

using namespace sysio;

class [[sysio::contract]] permission_tests : public contract {
public:
using contract::contract;

// Verify get_permission() convenience wrapper compiles and links.
// The intrinsic returns -1 when the permission is not found on-chain,
// so get_permission() returns std::nullopt.
[[sysio::action]]
void getperm( name account, name perm ) {
auto rec = get_permission( account, perm );
if( rec ) {
print("found perm=", rec->perm_name, " parent=", rec->parent,
" threshold=", rec->auth.threshold,
" keys=", rec->auth.keys.size(),
" accounts=", rec->auth.accounts.size());
} else {
print("not found");
}
}

// Verify the raw C intrinsic compiles and links.
[[sysio::action]]
void getpermraw( name account, name perm ) {
char buf[256];
int32_t sz = internal_use_do_not_use::get_permission_lower_bound(
account.value, perm.value, buf, sizeof(buf) );
if( sz > 0 && static_cast<uint32_t>(sz) <= sizeof(buf) ) {
auto rec = unpack<permission_record>( buf, static_cast<size_t>(sz) );
print("raw perm=", rec.perm_name);
} else {
print("raw not found, sz=", sz);
}
}

// Verify all the new types are usable in contract code.
[[sysio::action]]
void checktypes() {
perm_key_weight kw;
kw.weight = 1;

perm_level_weight lw;
lw.permission = permission_level{ "alice"_n, "active"_n };
lw.weight = 1;

perm_authority auth;
auth.threshold = 1;
auth.keys.push_back( kw );
auth.accounts.push_back( lw );

permission_record rec;
rec.perm_name = "active"_n;
rec.parent = "owner"_n;
rec.auth = auth;

// Round-trip serialize / deserialize
auto packed = pack( rec );
auto rec2 = unpack<permission_record>( packed );

check( rec2.perm_name == "active"_n, "perm_name mismatch" );
check( rec2.parent == "owner"_n, "parent mismatch" );
check( rec2.auth.threshold == 1, "threshold mismatch" );
check( rec2.auth.keys.size() == 1, "keys size mismatch" );
check( rec2.auth.accounts.size() == 1, "accounts size mismatch" );
check( rec2.auth.accounts[0].permission.actor == "alice"_n, "account actor mismatch" );

print("types ok");
}
};
Loading