genesis mint working

This commit is contained in:
Richard Holland
2023-06-05 12:08:59 +00:00
parent 01e298befe
commit 1ae08afb02
7 changed files with 428 additions and 3 deletions

View File

@@ -443,6 +443,7 @@ target_sources (rippled PRIVATE
src/ripple/app/tx/impl/SetRegularKey.cpp
src/ripple/app/tx/impl/SetHook.cpp
src/ripple/app/tx/impl/ClaimReward.cpp
src/ripple/app/tx/impl/GenesisMint.cpp
src/ripple/app/tx/impl/Import.cpp
src/ripple/app/tx/impl/Invoke.cpp
src/ripple/app/tx/impl/SetSignerList.cpp

View File

@@ -1,4 +1,4 @@
all: reward govern
all: reward govern mint
reward:
wasmcc reward.c -o reward.wasm -Oz -Wl,--allow-undefined -I../
wasm-opt reward.wasm -o reward.wasm \
@@ -109,3 +109,58 @@ govern:
-Oz
hook-cleaner govern.wasm
guard_checker govern.wasm
mint:
wasmcc mint.c -o mint.wasm -Oz -Wl,--allow-undefined -I../
wasm-opt mint.wasm -o mint.wasm \
--shrink-level=100000000 \
--coalesce-locals-learning \
--vacuum \
--merge-blocks \
--merge-locals \
--flatten \
--ignore-implicit-traps \
-ffm \
--const-hoisting \
--code-folding \
--code-pushing \
--dae-optimizing \
--dce \
--simplify-globals-optimizing \
--simplify-locals-nonesting \
--reorder-locals \
--rereloop \
--precompute-propagate \
--local-cse \
--remove-unused-brs \
--memory-packing \
-c \
--avoid-reinterprets \
-Oz
hook-cleaner mint.wasm
wasm-opt mint.wasm -o mint.wasm \
--shrink-level=100000000 \
--coalesce-locals-learning \
--vacuum \
--merge-blocks \
--merge-locals \
--flatten \
--ignore-implicit-traps \
-ffm \
--const-hoisting \
--code-folding \
--code-pushing \
--dae-optimizing \
--dce \
--simplify-globals-optimizing \
--simplify-locals-nonesting \
--reorder-locals \
--rereloop \
--precompute-propagate \
--local-cse \
--remove-unused-brs \
--memory-packing \
-c \
--avoid-reinterprets \
-Oz
hook-cleaner mint.wasm
guard_checker mint.wasm

114
hook/mint.c Normal file
View File

@@ -0,0 +1,114 @@
// This hook just tests GenesisMint transactor, it is not for production use
#include "hookapi.h"
#define ASSERT(x)\
if (!(x))\
rollback(SBUF("Reward: Assertion failure."),__LINE__);
#define DEBUG 1
uint8_t txn_mint[13844] =
{
/* size,upto */
/* 3, 0 */ 0x12U, 0x00U, 0x60U, /* tt = GenesisMint */
/* 5, 3 */ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* flags = tfCanonical */
/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* sequence = 0 */
/* 6, 13 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* first ledger seq */
/* 6, 19 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* last ledger seq */
/* 9, 25 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* fee */
/* 35, 34 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* pubkey */
/* 22, 69 */ 0x81U, 0x14U, 0xB5U,0xF7U,0x62U,0x79U,0x8AU,0x53U,0xD5U,0x43U,0xA0U,0x14U,
0xCAU,0xF8U,0xB2U,0x97U,0xCFU,0xF8U,0xF2U,0xF9U,0x37U,0xE8U, /* src acc */
/* 116, 91 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* emit detail */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* 207, ... */ 0xF0U, 0x60U, /* gen mints arr */
/* 34 bytes per entries + 1 tail byte
E060
61
4111111111111111 // amount
8114
1234567891234567891234567891234567891234 // account
E1
... repeat
F1 // tail byte
*
* */
};
#define BE_DROPS(drops)\
{\
uint64_t drops_tmp = drops;\
uint8_t* b = (uint8_t*)&drops;\
*b++ = 0b01000000 + (( drops_tmp >> 56 ) & 0b00111111 );\
*b++ = (drops_tmp >> 48) & 0xFFU;\
*b++ = (drops_tmp >> 40) & 0xFFU;\
*b++ = (drops_tmp >> 32) & 0xFFU;\
*b++ = (drops_tmp >> 24) & 0xFFU;\
*b++ = (drops_tmp >> 16) & 0xFFU;\
*b++ = (drops_tmp >> 8) & 0xFFU;\
*b++ = (drops_tmp >> 0) & 0xFFU;\
}
int64_t hook(uint32_t r)
{
etxn_reserve(1);
_g(1,1);
// emit the txn
uint64_t drops = 200;
BE_DROPS(drops);
uint8_t* upto = txn_mint + 209U;
*upto++ = 0xE0U; // obj start
*upto++ = 0x60U;
*upto++ = 0x61U; // amt
*((uint64_t*)upto) = drops;
upto += 8;
*upto++ = 0x83U; // acc
*upto++ = 0x14U;
otxn_field(upto, 20, sfDestination);
upto += 20;
*upto++ = 0xE1U; // obj end
*upto++ = 0xF1U; // array end
etxn_details(txn_mint + 91, 116);
int64_t fee = etxn_fee_base(txn_mint, upto - txn_mint);
BE_DROPS(fee);
*((uint64_t*)(txn_mint + 26)) = fee;
int64_t seq = ledger_seq() + 1;
txn_mint[15] = (seq >> 24U) & 0xFFU;
txn_mint[16] = (seq >> 16U) & 0xFFU;
txn_mint[17] = (seq >> 8U) & 0xFFU;
txn_mint[18] = seq & 0xFFU;
seq += 4;
txn_mint[21] = (seq >> 24U) & 0xFFU;
txn_mint[22] = (seq >> 16U) & 0xFFU;
txn_mint[23] = (seq >> 8U) & 0xFFU;
txn_mint[24] = seq & 0xFFU;
trace(SBUF("emit:"), txn_mint, upto-txn_mint, 1);
uint8_t emithash[32];
int64_t emit_result = emit(SBUF(emithash), txn_mint, upto - txn_mint);
if (DEBUG)
TRACEVAR(emit_result);
if (emit_result < 0)
rollback(SBUF("MintTest: Emit failed."), __LINE__);
accept(SBUF("MintTest: Emitted txn successfully."), __LINE__);
}

View File

@@ -0,0 +1,187 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/tx/impl/GenesisMint.h>
#include <ripple/basics/Log.h>
#include <ripple/ledger/View.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
TxConsequences
GenesisMint::makeTxConsequences(PreflightContext const& ctx)
{
// RH TODO: review this
return TxConsequences{ctx.tx, TxConsequences::normal};
}
NotTEC
GenesisMint::preflight(PreflightContext const& ctx)
{
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;
auto& tx = ctx.tx;
auto const id = ctx.tx[sfAccount];
static auto const genesisAccountId = calcAccountID(
generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase"))
.first);
if (id != genesisAccountId || !tx.isFieldPresent(sfEmitDetails))
{
JLOG(ctx.j.warn())
<< "GenesisMint: can only be used by the genesis account in an emitted transaction.";
return temMALFORMED;
}
auto const& dests = tx.getFieldArray(sfGenesisMints);
if (dests.empty())
{
JLOG(ctx.j.warn())
<< "GenesisMint: destinations array empty.";
return temMALFORMED;
}
if (dests.size() > 512)
{
JLOG(ctx.j.warn())
<< "GenesisMint: destinations array exceeds 512 entries.";
return temMALFORMED;
}
std::unordered_set<AccountID> alreadySeen;
for (auto const& dest: dests)
{
if (dest.getFName() != sfGenesisMint)
{
JLOG(ctx.j.warn())
<< "GenesisMint: destinations array contained an invalid entry.";
return temMALFORMED;
}
auto const amt = dest.getFieldAmount(sfAmount);
if (!isXRP(amt))
{
JLOG(ctx.j.warn())
<< "GenesisMint: only native amounts can be minted.";
return temMALFORMED;
}
if (amt <= beast::zero)
{
JLOG(ctx.j.warn())
<< "GenesisMint: only positive amounts can be minted.";
return temMALFORMED;
}
auto const accid = dest.getAccountID(sfDestination);
if (accid == noAccount() || accid == xrpAccount())
{
JLOG(ctx.j.warn())
<< "GenesisMint: destinations includes disallowed account zero or one.";
return temMALFORMED;
}
if (alreadySeen.find(accid) != alreadySeen.end())
{
JLOG(ctx.j.warn())
<< "GenesisMint: duplicate in destinations.";
return temMALFORMED;
}
alreadySeen.emplace(accid);
}
return preflight2(ctx);
}
TER
GenesisMint::preclaim(PreclaimContext const& ctx)
{
if (!ctx.view.rules().enabled(featureHooks))
return temDISABLED;
if (!ctx.view.rules().enabled(featureXahauGenesis))
return temDISABLED;
// RH UPTO:
// check that printing won't exceed 200% of the total coins on the ledger
// this will act as a hard cap against malfunction
// modify the invariant checkers
return tesSUCCESS;
}
TER
GenesisMint::doApply()
{
auto const& dests = ctx_.tx.getFieldArray(sfGenesisMints);
for (auto const& dest: dests)
{
auto const amt = dest.getFieldAmount(sfAmount);
auto const id = dest.getAccountID(sfDestination);
auto const k = keylet::account(id);
auto sle = view().peek(k);
if (!sle)
{
// Create the account.
std::uint32_t const seqno{
view().rules().enabled(featureDeletableAccounts) ? view().seq()
: 1};
sle = std::make_shared<SLE>(k);
sle->setAccountID(sfAccount, id);
sle->setFieldU32(sfSequence, seqno);
sle->setFieldAmount(sfBalance, amt);
view().insert(sle);
}
else
{
// Credit the account
STAmount startBal = sle->getFieldAmount(sfBalance);
STAmount finalBal = startBal + amt;
if (finalBal > startBal)
{
sle->setFieldAmount(sfBalance, finalBal);
view().update(sle);
}
else
{
JLOG(ctx_.journal.warn())
<< "GenesisMint: cannot credit " << dest << " due to balance overflow";
}
}
}
return tesSUCCESS;
}
XRPAmount
GenesisMint::calculateBaseFee(ReadView const& view, STTx const& tx)
{
return Transactor::calculateBaseFee(view, tx);
}
} // namespace ripple

View File

@@ -0,0 +1,57 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TX_GENESISMINT_H_INCLUDED
#define RIPPLE_TX_GENESISMINT_H_INCLUDED
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class GenesisMint : public Transactor
{
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
explicit GenesisMint(ApplyContext& ctx) : Transactor(ctx)
{
}
static XRPAmount
calculateBaseFee(ReadView const& view, STTx const& tx);
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);
static TER
preclaim(PreclaimContext const& ctx);
TER
doApply() override;
};
} // namespace ripple
#endif

View File

@@ -44,6 +44,7 @@
#include <ripple/app/tx/impl/Import.h>
#include <ripple/app/tx/impl/Invoke.h>
#include <ripple/app/tx/impl/URIToken.h>
#include <ripple/app/tx/impl/GenesisMint.h>
namespace ripple {
@@ -156,6 +157,8 @@ invoke_preflight(PreflightContext const& ctx)
return invoke_preflight_helper<NFTokenAcceptOffer>(ctx);
case ttCLAIM_REWARD:
return invoke_preflight_helper<ClaimReward>(ctx);
case ttGENESIS_MINT:
return invoke_preflight_helper<GenesisMint>(ctx);
case ttIMPORT:
return invoke_preflight_helper<Import>(ctx);
case ttINVOKE:
@@ -275,6 +278,8 @@ invoke_preclaim(PreclaimContext const& ctx)
return invoke_preclaim<NFTokenAcceptOffer>(ctx);
case ttCLAIM_REWARD:
return invoke_preclaim<ClaimReward>(ctx);
case ttGENESIS_MINT:
return invoke_preclaim<GenesisMint>(ctx);
case ttIMPORT:
return invoke_preclaim<Import>(ctx);
case ttINVOKE:
@@ -353,6 +358,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
return NFTokenAcceptOffer::calculateBaseFee(view, tx);
case ttCLAIM_REWARD:
return ClaimReward::calculateBaseFee(view, tx);
case ttGENESIS_MINT:
return GenesisMint::calculateBaseFee(view, tx);
case ttIMPORT:
return Import::calculateBaseFee(view, tx);
case ttINVOKE:
@@ -525,6 +532,10 @@ invoke_apply(ApplyContext& ctx)
ClaimReward p(ctx);
return p();
}
case ttGENESIS_MINT: {
GenesisMint p(ctx);
return p();
}
case ttIMPORT: {
Import p(ctx);
return p();

View File

@@ -336,7 +336,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfHookExecution, "HookExecution", OBJECT,
CONSTRUCT_UNTYPED_SFIELD(sfHookDefinition, "HookDefinition", OBJECT, 22);
CONSTRUCT_UNTYPED_SFIELD(sfHookParameter, "HookParameter", OBJECT, 23);
CONSTRUCT_UNTYPED_SFIELD(sfHookGrant, "HookGrant", OBJECT, 24);
CONSTRUCT_UNTYPED_SFIELD(sfGenesisMint, "GenesisMint", OBJECT, 25);
CONSTRUCT_UNTYPED_SFIELD(sfGenesisMint, "GenesisMint", OBJECT, 96);
// array of objects
// ARRAY/1 is reserved for end of array
@@ -357,7 +357,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfDisabledValidators, "DisabledValidators", ARRAY,
CONSTRUCT_UNTYPED_SFIELD(sfHookExecutions, "HookExecutions", ARRAY, 18);
CONSTRUCT_UNTYPED_SFIELD(sfHookParameters, "HookParameters", ARRAY, 19);
CONSTRUCT_UNTYPED_SFIELD(sfHookGrants, "HookGrants", ARRAY, 20);
CONSTRUCT_UNTYPED_SFIELD(sfGenesisMints, "GenesisMints", ARRAY, 21);
CONSTRUCT_UNTYPED_SFIELD(sfGenesisMints, "GenesisMints", ARRAY, 96);
// clang-format on