Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement register and unregister on wallet API, add tests #1741

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions wallet/api/v6_0/wallet_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ namespace beam::wallet
}
}

template<typename T>
void onHandleRegisterUnregister(bool doRegister, const JsonRpcId &id, const T& data);

template<typename T>
void onHandleIssueConsume(bool issue, const JsonRpcId& id, const T& data);

Expand All @@ -135,6 +138,8 @@ namespace beam::wallet
WALLET_API_METHODS(PARSE_FUNC)
#undef PARSE_FUNC

template<typename T>
std::pair<T, IWalletApi::MethodInfo> onParseRegisterUnregister(bool doRegister, const JsonRpcId& id, const json& params);
template<typename T>
std::pair<T, IWalletApi::MethodInfo> onParseIssueConsume(bool issue, const JsonRpcId& id, const json& params);

Expand Down
28 changes: 28 additions & 0 deletions wallet/api/v6_0/wallet_api_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ namespace beam::wallet
macro(AddrList, "addr_list", API_READ_ACCESS, API_SYNC, APPS_ALLOWED) \
macro(ValidateAddress, "validate_address", API_READ_ACCESS, API_SYNC, APPS_ALLOWED) \
macro(Send, "tx_send", API_WRITE_ACCESS, API_SYNC, APPS_ALLOWED) \
macro(Register, "tx_asset_register", API_WRITE_ACCESS, API_SYNC, APPS_ALLOWED /* TODO: I feel like apps shouldn't be allowed to do this, but I also don't know what this refers to in "apps". */) \
macro(Unregister, "tx_asset_unregister", API_WRITE_ACCESS, API_SYNC, APPS_ALLOWED) \
macro(Issue, "tx_asset_issue", API_WRITE_ACCESS, API_SYNC, APPS_BLOCKED) \
macro(Consume, "tx_asset_consume", API_WRITE_ACCESS, API_SYNC, APPS_BLOCKED) \
macro(TxAssetInfo, "tx_asset_info", API_WRITE_ACCESS, API_SYNC, APPS_ALLOWED) \
Expand Down Expand Up @@ -172,6 +174,32 @@ namespace beam::wallet
};
};

struct Register
{
Amount fee = 0;
std::string asset_meta;
boost::optional<CoinIDList> coins;
boost::optional<TxID> txId;

struct Response
{
TxID txId;
};
};

struct Unregister
{
Amount fee = 0;
std::string asset_meta;
boost::optional<CoinIDList> coins;
boost::optional<TxID> txId;

struct Response
{
TxID txId;
};
};

struct Issue
{
Amount value = 0;
Expand Down
42 changes: 42 additions & 0 deletions wallet/api/v6_0/wallet_api_handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,48 @@ namespace beam::wallet
template void WalletApi::setTxAssetParams(const JsonRpcId& id, TxParameters& params, const Issue& data);
template void WalletApi::setTxAssetParams(const JsonRpcId& id, TxParameters& params, const Consume& data);

void WalletApi::onHandleRegister(const JsonRpcId &id, const Register &data)
{
WalletApi::onHandleRegisterUnregister(false, id, data);
}

void WalletApi::onHandleUnregister(const JsonRpcId &id, const Unregister &data)
{
WalletApi::onHandleRegisterUnregister(false, id, data);
}

template <typename T>
void WalletApi::onHandleRegisterUnregister(bool doRegister, const JsonRpcId& id, const T& data)
{
try {
auto walletDB = getWalletDB();
auto wallet = getWallet();
CoinIDList coins = data.coins ? *data.coins : CoinIDList();

WalletAssetMeta meta(data.asset_meta);

if (data.txId && walletDB->getTx(*data.txId)) {
doTxAlreadyExistsError(id);
return;
}

auto params = CreateTransactionParameters(doRegister ? TxType::AssetReg : TxType::AssetUnreg)
.SetParameter(TxParameterID::Amount, Rules::get().CA.DepositForList)
.SetParameter(TxParameterID::Fee, data.fee)
.SetParameter(TxParameterID::PreselectedCoins, coins)
.SetParameter(TxParameterID::AssetMetadata, data.asset_meta);

const auto txId = wallet->StartTransaction(params);
doResponse(id, Register::Response{txId});
} catch(const jsonrpc_exception&) {
throw;
}
catch (...)
{
throw jsonrpc_exception(ApiError::InternalErrorJsonRpc, "Transaction could not be created. Please look at logs.");
}
}

void WalletApi::onHandleIssue(const JsonRpcId& id, const Issue& data)
{
onHandleIssueConsume(true, id, data);
Expand Down
86 changes: 86 additions & 0 deletions wallet/api/v6_0/wallet_api_parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,64 @@ namespace beam::wallet
return std::make_pair(txDelete, MethodInfo());
}

std::pair<Register, IWalletApi::MethodInfo> WalletApi::onParseRegister(const JsonRpcId& id, const json& params)
{
return onParseRegisterUnregister<Register>(false, id, params);
}

std::pair<Unregister, IWalletApi::MethodInfo> WalletApi::onParseUnregister(const JsonRpcId& id, const json& params)
{
return onParseRegisterUnregister<Unregister>(false, id, params);
}

template <typename T>
std::pair<T, IWalletApi::MethodInfo> WalletApi::onParseRegisterUnregister(bool doRegister, const JsonRpcId& id, const json& params)
{
T data;
data.asset_meta = getMandatoryParam<std::string>(params, "asset_meta");

WalletAssetMeta meta(data.asset_meta);
// ensure that asset meta has all required parameters at a minimum
const auto chkMetadata = [&](bool cond, const std::string& param) -> auto {
if (cond) {
throw jsonrpc_exception(ApiError::InvalidParamsJsonRpc, param + " is a required asset descriptor, but was not included.");
}
};

chkMetadata(meta.GetSchemaVersion() == 0, "SCH_VER");
chkMetadata(meta.GetName().empty(), "N");
chkMetadata(meta.GetShortName().empty(), "SN");
chkMetadata(meta.GetUnitName().empty(), "UN");
chkMetadata(meta.GetNthUnitName().empty(), "NTHUN");

if (hasParam(params, "coins"))
{
data.coins = readCoinsParameter(id, params);
}

data.fee = getBeamFeeParam(params, "fee");
data.txId = getOptionalParam<ValidTxID>(params, "txId");

MethodInfo info;
info.fee = data.fee;

if (doRegister)
{
// is there an actual Beam to Groth value somewhere in wallet API source?
// additionally, is this correct behaviour?
info.spend[Asset::s_BeamID] = (Amount) 3000 * 100000000;
}
else
{
info.receive[Asset::s_BeamID] = (Amount) 3000 * 100000000;
}

return std::make_pair(data, info);
}

template std::pair<Register, IWalletApi::MethodInfo> WalletApi::onParseRegisterUnregister(bool doRegister, const JsonRpcId& id, const json& params);
template std::pair<Unregister, IWalletApi::MethodInfo> WalletApi::onParseRegisterUnregister(bool doRegister, const JsonRpcId& id, const json& params);

std::pair<Issue, IWalletApi::MethodInfo> WalletApi::onParseIssue(const JsonRpcId& id, const json& params)
{
return onParseIssueConsume<Issue>(true, id, params);
Expand Down Expand Up @@ -1085,6 +1143,34 @@ namespace beam::wallet
};
}

void WalletApi::getResponse(const JsonRpcId& id, const Register::Response& res, json& msg)
{
msg = json
{
{JsonRpcHeader, JsonRpcVersion},
{"id", id},
{"result",
{
{"txId", std::to_string(res.txId)}
}
}
};
}

void WalletApi::getResponse(const JsonRpcId& id, const Unregister::Response& res, json& msg)
{
msg = json
{
{JsonRpcHeader, JsonRpcVersion},
{"id", id},
{"result",
{
{"txId", std::to_string(res.txId)}
}
}
};
}

void WalletApi::getResponse(const JsonRpcId& id, const Issue::Response& res, json& msg)
{
msg = json
Expand Down
2 changes: 1 addition & 1 deletion wallet/core/assets_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ namespace beam::wallet {

unsigned WalletAssetMeta::GetSchemaVersion() const
{
const auto it = _values.find(SHORT_NAME_KEY);
const auto it = _values.find(VERSION_KEY);
return it != _values.end() ? std::to_unsigned(it->second, false) : 0;
}

Expand Down
84 changes: 84 additions & 0 deletions wallet/unittests/wallet_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,42 @@ namespace
WALLET_CHECK(ApiSyncMode::DoneSync == api.executeAPIRequest(msg.data(), msg.size()));
}

// confidential assets register/unregister test
template<typename T>
void testCA_R_UR(const std::string& msg) {
class ApiTest : public WalletApiTest
{
public:
void onAPIError(const json& msg) override {
cout << msg["error"] << endl;
WALLET_CHECK(!"invalid register/unregister api json!!!");
}

void onHandleRegister(const JsonRpcId& id, const Register& data) override {
WALLET_CHECK(id > 0);
WALLET_CHECK(!data.asset_meta.empty());
}

void onHandleUnregister(const JsonRpcId& id, const Unregister& data) override {
WALLET_CHECK(id > 0);
WALLET_CHECK(!data.asset_meta.empty());
}
};

ApiTest api;
WALLET_CHECK(ApiSyncMode::DoneSync == api.executeAPIRequest(msg.data(), msg.size()));

{
json res;
typename T::Response status;
status.txId = {1,2,3};
api.getResponse(12345, status, res);
testResultHeader(res);

WALLET_CHECK(res["id"] == 12345);
}
}

template<typename T>
void testICJsonRpc(const std::string& msg)
{
Expand Down Expand Up @@ -924,6 +960,52 @@ namespace
#endif // BEAM_ATOMIC_SWAP_SUPPORT
}

template<typename T>
void TestCA_R_URTx(const char *method) {
const auto exp = [&](std::string str) -> auto {
const char* what = "METHOD";
const auto index = str.find(what);
if (index != std::string::npos) {
const std::string mname = std::string("\"") + method + "\"";
str.replace(index, strlen(what), mname);
}
return str;
};

testInvalidAssetJsonRpc<T>(exp(JSON_CODE(
{
"jsonrpc" : "2.0",
"id" : 12345,
"method" : METHOD,
"params" :
{
"asset_meta": ""
}
}
)));

testInvalidAssetJsonRpc<T>(exp(JSON_CODE(
{
"jsonrpc" : "2.0",
"id" : 12345,
"method" : METHOD,
"params" : {}
}
)));

testCA_R_UR<T>(exp(JSON_CODE(
{
"jsonrpc" : "2.0",
"id" : 12345,
"method" : METHOD,
"params" :
{
"asset_meta": "STD:SCH_VER=1;N=Test coin;SN=TEST;UN=Test;NTHUN=Groth"
}
}
)));
}

template<typename T>
void TestICTx(const char* method)
{
Expand Down Expand Up @@ -1295,6 +1377,8 @@ void TestAssetsAPI()
Rules::get().CA.Enabled = true;
Rules::get().UpdateChecksum();

TestCA_R_URTx<Register>("tx_asset_register");
TestCA_R_URTx<Unregister>("tx_asset_unregister");
TestICTx<Issue>("tx_asset_issue");
TestICTx<Consume>("tx_asset_consume");
TestAITx();
Expand Down