diff --git a/bvm/bvm2.cpp b/bvm/bvm2.cpp index 908eb2dc0..c2f30be90 100644 --- a/bvm/bvm2.cpp +++ b/bvm/bvm2.cpp @@ -131,15 +131,6 @@ namespace bvm2 { get_CidViaSid(cid, sid, args); } - void get_AssetOwner(PeerID& pidOwner, const ContractID& cid, const Asset::Metadata& md) - { - ECC::Hash::Processor() - << "bvm.a.own" - << cid - << md.m_Hash - >> pidOwner; - } - ///////////////////////////////////////////// // Processor #pragma pack (push, 1) @@ -1516,7 +1507,7 @@ namespace bvm2 { md.UpdateHash(); AssetVar av; - get_AssetOwner(av.m_Owner, m_FarCalls.m_Stack.back().m_Cid, md); + md.get_Owner(av.m_Owner, m_FarCalls.m_Stack.back().m_Cid); Amount valDeposit; Asset::ID ret = AssetCreate(md, av.m_Owner, valDeposit); diff --git a/bvm/bvm2.h b/bvm/bvm2.h index e6830174d..261d8b301 100644 --- a/bvm/bvm2.h +++ b/bvm/bvm2.h @@ -25,11 +25,11 @@ namespace Shaders { typedef ECC::Point::Storage Secp_point_dataEx; typedef ECC::Scalar Secp_scalar_data; typedef beam::Asset::ID AssetID; - typedef ECC::uintBig ContractID; typedef ECC::uintBig ShaderID; typedef ECC::uintBig HashValue; typedef beam::uintBig_t<64> HashValue512; - using beam::Amount; + using beam::ContractID; + using beam::Amount; using beam::Height; using beam::Timestamp; using beam::HeightPos; @@ -102,8 +102,6 @@ namespace bvm2 { void get_Cid(ContractID&, const Blob& data, const Blob& args); void get_CidViaSid(ContractID&, const ShaderID&, const Blob& args); - void get_AssetOwner(PeerID&, const ContractID&, const Asset::Metadata&); - class ProcessorContract; class Processor diff --git a/bvm/invoke_data.h b/bvm/invoke_data.h index f477fdfdd..ba8e80eee 100644 --- a/bvm/invoke_data.h +++ b/bvm/invoke_data.h @@ -27,7 +27,7 @@ namespace beam::bvm2 { struct ContractInvokeEntry { uint32_t m_Flags = 0; - ECC::uintBig m_Cid; + ContractID m_Cid; uint32_t m_iMethod = 0; ByteBuffer m_Data; ByteBuffer m_Args; diff --git a/core/block_crypt.cpp b/core/block_crypt.cpp index fb6d11667..f0f4dd3a3 100644 --- a/core/block_crypt.cpp +++ b/core/block_crypt.cpp @@ -2937,10 +2937,19 @@ namespace beam { m_Value = Zero; m_Owner = Zero; + m_Cid = Zero; m_LockHeight = 0; m_Metadata.Reset(); } + void Asset::Info::SetCid(const ContractID* pCid) + { + if (pCid) + m_Cid = *pCid; + else + m_Cid = Zero; + } + bool Asset::Info::IsEmpty() const { return m_Value == Zero && m_Owner == Zero && m_LockHeight == Zero && m_Metadata.m_Value.empty(); @@ -3052,6 +3061,15 @@ namespace beam res.Import(pt); } + void Asset::Metadata::get_Owner(PeerID& res, const ContractID& cid) const + { + ECC::Hash::Processor() + << "bvm.a.own" + << cid + << m_Hash + >> res; + } + bool Asset::Info::Recognize(Key::IPKdf& pkdf) const { PeerID pid; diff --git a/core/block_crypt.h b/core/block_crypt.h index 432821f9d..ac0fca6e5 100644 --- a/core/block_crypt.h +++ b/core/block_crypt.h @@ -44,6 +44,8 @@ namespace beam using ECC::Key; + typedef ECC::uintBig ContractID; + namespace MasterKey { Key::IKdf::Ptr get_Child(Key::IKdf&, Key::Index); @@ -174,18 +176,21 @@ namespace beam void Reset(); void UpdateHash(); // called automatically during deserialization void get_Owner(PeerID&, Key::IPKdf&) const; + void get_Owner(PeerID&, const ContractID&) const; }; struct Info { AmountBig::Type m_Value = Zero; PeerID m_Owner = Zero; + ContractID m_Cid = Zero; Height m_LockHeight = 0; // last emitted/burned change height. if emitted atm - when was latest 1st emission. If burned atm - what was last burn. Amount m_Deposit = 0; Metadata m_Metadata; static const uint32_t s_MetadataMaxSize = 1024 * 16; // 16K void Reset(); + void SetCid(const ContractID*); bool IsEmpty() const; bool IsValid() const; bool Recognize(Key::IPKdf&) const; @@ -1139,7 +1144,7 @@ namespace beam struct TxKernelContractInvoke :public TxKernelContractControl { - ECC::uintBig m_Cid; + ContractID m_Cid; uint32_t m_iMethod; typedef std::unique_ptr Ptr; diff --git a/core/fly_client.cpp b/core/fly_client.cpp index 3b1b2905b..c0fbac2c4 100644 --- a/core/fly_client.cpp +++ b/core/fly_client.cpp @@ -880,14 +880,6 @@ bool FlyClient::NetworkStd::Connection::IsSupported(RequestTransaction& req) return true; } -bool FlyClient::NetworkStd::Connection::IsSupported(RequestAssetsListAt& req) -{ - if (get_Ext() < 10) - return false; - - return true; -} - void FlyClient::NetworkStd::Connection::OnRequestData(RequestProofShieldedInp& req) { if (!req.m_Res.m_Proof.empty()) @@ -1084,6 +1076,15 @@ bool FlyClient::NetworkStd::Connection::SendRequest(RequestBbsMsg& req) return true; } +bool FlyClient::NetworkStd::Connection::SendRequest(RequestAssetsListAt& req) +{ + if (get_Ext() < 10) + return false; + + Send(req.m_Msg); + return true; +} + void FlyClient::NetworkStd::Connection::OnMsg(proto::Pong&&) { if (!m_lst.empty()) @@ -1112,6 +1113,42 @@ void FlyClient::NetworkStd::Connection::OnMsg(proto::Pong&&) } } +void FlyClient::NetworkStd::Connection::OnMsg(proto::AssetsListAt&& msg) +{ + auto& n = get_FirstRequest(); + auto& r = n.m_pRequest->As(); + + if (msg.m_Assets.empty()) + { + if (msg.m_bMore) + ThrowUnexpected(); + } + else + { + Asset::ID aid0 = r.m_Msg.m_Aid0; + for (const auto& ai : msg.m_Assets) + { + if (aid0 > ai.m_ID) + ThrowUnexpected(); + + aid0 = ai.m_ID + 1; + } + + if (r.m_Res.empty()) + r.m_Res = std::move(msg.m_Assets); + else + r.m_Res.insert(r.m_Res.end(), msg.m_Assets.begin(), msg.m_Assets.end()); + + + r.m_Msg.m_Aid0 = aid0; + } + + + if (msg.m_bMore) + Send(r.m_Msg); + else + OnDone(n); +} void FlyClient::NetworkStd::Connection::OnDone(RequestNode& n, bool bMaybeRetry /* = true */) { diff --git a/core/fly_client.h b/core/fly_client.h index 9b3e9202e..9b95300f8 100644 --- a/core/fly_client.h +++ b/core/fly_client.h @@ -63,7 +63,6 @@ namespace proto { macro(ShieldedOutputsAt, GetShieldedOutputsAt, ShieldedOutputsAt) \ macro(BodyPack, GetBodyPack, BodyPack) \ macro(Body, GetBodyPack, Body) \ - macro(AssetsListAt, GetAssetsListAt, AssetsListAt) \ class Request @@ -140,6 +139,10 @@ namespace proto { struct EnsureSync { bool m_IsDependent; }; + struct AssetsListAt { + proto::GetAssetsListAt m_Msg; + std::vector m_Res; + }; }; #define THE_MACRO(type) \ @@ -320,11 +323,11 @@ namespace proto { void OnMsg(proto::HdrPack&& msg) override; void OnMsg(proto::ContractVars&& msg) override; void OnMsg(proto::ContractLogs&& msg) override; + void OnMsg(proto::AssetsListAt&& msg) override; bool IsSupported(const Data::Std&) { return true; } bool IsSupported(RequestEvents&); bool IsSupported(RequestTransaction&); - bool IsSupported(RequestAssetsListAt&); void OnRequestData(const Data::Std&) {} void OnRequestData(RequestUtxo&); diff --git a/core/proto.h b/core/proto.h index 43dd12835..41a5b480f 100644 --- a/core/proto.h +++ b/core/proto.h @@ -259,10 +259,12 @@ namespace proto { macro(TxoID, ShieldedOuts) #define BeamNodeMsg_GetAssetsListAt(macro) \ - macro(Height, Height) + macro(Height, Height) \ + macro(Asset::ID, Aid0) #define BeamNodeMsg_AssetsListAt(macro) \ - macro(ByteBuffer, AssetsList) + macro(std::vector, Assets) \ + macro(bool, bMore) #define BeamNodeMsg_ContractVarsEnum(macro) \ macro(ByteBuffer, KeyMin) \ diff --git a/core/serialization_adapters.h b/core/serialization_adapters.h index 375c42ad4..f99577686 100644 --- a/core/serialization_adapters.h +++ b/core/serialization_adapters.h @@ -1970,21 +1970,32 @@ namespace detail template Archive& save(Archive& ar, const beam::Asset::Info& v) { - bool bDef = v.IsDefDeposit(); - beam::Height h = bDef ? v.m_LockHeight : beam::MaxHeight; + uint32_t nFlags = 0; + if (!v.IsDefDeposit()) + nFlags |= 1; + + const ECC::uintBig* pOwner = &v.m_Owner; + if (v.m_Cid != beam::Zero) + { + pOwner = &v.m_Cid; + nFlags |= 2; + } + + beam::Height h = nFlags ? beam::MaxHeight : v.m_LockHeight; ar - & v.m_Owner + & (*pOwner) & v.m_Value & h & v.m_Metadata; - if (!bDef) + if (nFlags) { - uint32_t nFlags = 1; // reserve other flags for future use ar & nFlags - & v.m_LockHeight - & v.m_Deposit; + & v.m_LockHeight; + + if (1 & nFlags) + ar & v.m_Deposit; } return ar; @@ -2000,6 +2011,7 @@ namespace detail & v.m_Metadata; v.m_Deposit = beam::Rules::get().CA.DepositForList2; + v.m_Cid = beam::Zero; if (beam::MaxHeight == v.m_LockHeight) { @@ -2010,6 +2022,12 @@ namespace detail if (1 & nFlags) ar & v.m_Deposit; + + if (2 & nFlags) + { + v.m_Cid = Cast::Down(v.m_Owner); + v.m_Metadata.get_Owner(v.m_Owner, v.m_Cid); + } } return ar; diff --git a/node/db.cpp b/node/db.cpp index 59e1e3565..0742bb7bb 100644 --- a/node/db.cpp +++ b/node/db.cpp @@ -98,6 +98,7 @@ namespace beam { #define TblAssets "Assets" #define TblAssets_ID "ID" #define TblAssets_Owner "Owner" +#define TblAssets_Cid "Cid" #define TblAssets_Value "Value" #define TblAssets_Data "MetaData" #define TblAssets_Deposit "Deposit" @@ -367,7 +368,7 @@ void NodeDB::Open(const char* szPath) bCreate = !rs.Step(); } - const uint64_t nVersionTop = 32; + const uint64_t nVersionTop = 33; Transaction t(*this); @@ -442,6 +443,7 @@ void NodeDB::Open(const char* szPath) // no break; case 31: + case 32: ExecQuick("DROP TABLE IF EXISTS " TblAssets); CreateTables31(); @@ -650,6 +652,7 @@ void NodeDB::CreateTables31() ExecQuick("CREATE TABLE [" TblAssets "] (" "[" TblAssets_ID "] INTEGER NOT NULL PRIMARY KEY," "[" TblAssets_Owner "] BLOB," + "[" TblAssets_Cid "] BLOB," "[" TblAssets_Data "] BLOB," "[" TblAssets_Deposit "] INTEGER," "[" TblAssets_LockHeight "] INTEGER," @@ -1483,6 +1486,15 @@ void NodeDB::set_StateTxosAndExtra(uint64_t rowid, const TxoID* pId, const Blob* TestChanged1Row(); } +void NodeDB::set_StateRB(uint64_t rowid, const Blob& rb) +{ + Recordset rs(*this, Query::StateSetRB, "UPDATE " TblStates " SET " TblStates_Rollback "=? WHERE rowid=?"); + rs.put(0, rb); + rs.put(1, rowid); + rs.Step(); + TestChanged1Row(); +} + TxoID NodeDB::get_StateTxos(uint64_t rowid) { Recordset rs(*this, Query::StateGetTxos, "SELECT " TblStates_Txos " FROM " TblStates " WHERE rowid=?"); @@ -2726,16 +2738,18 @@ void NodeDB::AssetDeleteRaw(Asset::ID id) void NodeDB::AssetInsertRaw(Asset::ID id, const Asset::Full* pAi) { - Recordset rs(*this, Query::AssetAdd, "INSERT INTO " TblAssets "(" TblAssets_ID "," TblAssets_Owner "," TblAssets_Data "," TblAssets_Deposit "," TblAssets_Value "," TblAssets_LockHeight ") VALUES(?,?,?,?,?,?)"); + Recordset rs(*this, Query::AssetAdd, "INSERT INTO " TblAssets "(" TblAssets_ID "," TblAssets_Owner "," TblAssets_Cid "," TblAssets_Data "," TblAssets_Deposit "," TblAssets_Value "," TblAssets_LockHeight ") VALUES(?,?,?,?,?,?,?)"); rs.put(0, id); if (pAi) { rs.put(1, pAi->m_Owner); - rs.put(2, Blob(pAi->m_Metadata.m_Value)); - rs.put(3, pAi->m_Deposit); - rs.put_As(4, pAi->m_Value); - rs.put(5, pAi->m_LockHeight); + if (pAi->m_Cid != Zero) + rs.put(2, pAi->m_Cid); + rs.put(3, Blob(pAi->m_Metadata.m_Value)); + rs.put(4, pAi->m_Deposit); + rs.put_As(5, pAi->m_Value); + rs.put(6, pAi->m_LockHeight); } rs.Step(); @@ -2822,16 +2836,22 @@ void NodeDB::AssetsDelAll() bool NodeDB::AssetGetSafe(Asset::Full& ai) { - Recordset rs(*this, Query::AssetGet, "SELECT " TblAssets_Value "," TblAssets_Owner "," TblAssets_Data "," TblAssets_Deposit "," TblAssets_LockHeight " FROM " TblAssets " WHERE " TblAssets_ID "=?"); + Recordset rs(*this, Query::AssetGet, "SELECT " TblAssets_Value "," TblAssets_Owner "," TblAssets_Cid "," TblAssets_Data "," TblAssets_Deposit "," TblAssets_LockHeight " FROM " TblAssets " WHERE " TblAssets_ID "=?"); rs.put(0, ai.m_ID); if (!rs.Step()) return false; rs.get_As(0, ai.m_Value); rs.get_As(1, ai.m_Owner); - rs.get(2, ai.m_Metadata.m_Value); - rs.get(3, ai.m_Deposit); - rs.get(4, ai.m_LockHeight); + + if (rs.IsNull(2)) + ai.m_Cid = Zero; + else + rs.get_As(2, ai.m_Cid); + + rs.get(3, ai.m_Metadata.m_Value); + rs.get(4, ai.m_Deposit); + rs.get(5, ai.m_LockHeight); ai.m_Metadata.UpdateHash(); diff --git a/node/db.h b/node/db.h index a3c7484d8..474ad5ea3 100644 --- a/node/db.h +++ b/node/db.h @@ -108,6 +108,7 @@ class NodeDB StateSetInputs, StateGetInputs, StateSetTxosAndExtra, + StateSetRB, StateGetTxos, StateFindByTxos, TipAdd, @@ -352,6 +353,7 @@ class NodeDB TxoID get_StateTxos(uint64_t rowid); void set_StateTxosAndExtra(uint64_t rowid, const TxoID*, const Blob* pExtra, const Blob* pRB); + void set_StateRB(uint64_t rowid, const Blob& rb); void SetStateBlock(uint64_t rowid, const Blob& bodyP, const Blob& bodyE, const PeerID&); void GetStateBlock(uint64_t rowid, ByteBuffer* pP, ByteBuffer* pE, ByteBuffer* pRB); diff --git a/node/node.cpp b/node/node.cpp index c61c9bff4..a87c526c5 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -3483,6 +3483,9 @@ void Node::Peer::OnMsg(proto::GetProofAsset&& msg) { msgOut.m_Info = std::move(ai); + if (get_Ext() < 10) + msgOut.m_Info.SetCid(nullptr); + p.m_Mmr.m_Assets.get_Proof(msgOut.m_Proof, msgOut.m_Info.m_ID - 1); struct MyProofBuilder @@ -3937,29 +3940,44 @@ void Node::Peer::OnMsg(proto::GetShieldedOutputsAt&& msg) void Node::Peer::OnMsg(proto::GetAssetsListAt&& msg) { - auto& processor = m_This.m_Processor; - auto height = msg.m_Height; + proto::AssetsListAt msgOut; - if(processor.m_Cursor.m_ID.m_Height < height) return; - - std::vector assets = {Asset::s_BeamID}; Asset::Full ai; - for (ai.m_ID = 1; ; ai.m_ID++) + ai.m_ID = msg.m_Aid0 ? (msg.m_Aid0 - 1) : 0; + + bool bCurrent = (msg.m_Height >= m_This.m_Processor.m_Cursor.m_Full.m_Height); + bool bLegacy = (get_Ext() < 10); + + while (ai.m_ID < Asset::s_MaxCount) { - int ret = processor.get_AssetAt(ai, height); - if (!ret) - break; + if (bCurrent) + { + if (!m_This.m_Processor.get_DB().AssetGetNext(ai)) + break; + } + else + { + ++ai.m_ID; + int ret = m_This.m_Processor.get_AssetAt(ai, msg.m_Height); + if (!ret) + break; - if (ret > 0) + if (ret < 0) + continue; + } + + if (msgOut.m_Assets.size() >= 3000) { - assets.push_back(ai.m_ID); + msgOut.m_bMore = true; + break; } + + if (bLegacy) + ai.SetCid(nullptr); + + msgOut.m_Assets.push_back(std::move(ai)); } - proto::AssetsListAt msgOut; - size_t assetsBufferSize = sizeof(Asset::ID) * assets.size(); - msgOut.m_AssetsList.resize(assetsBufferSize); - memcpy(msgOut.m_AssetsList.data(), assets.data(), assetsBufferSize); Send(msgOut); } @@ -5033,7 +5051,12 @@ bool Node::GenerateRecoveryInfo(const char* szPath) ai.m_ID = 0; while (m_Processor.get_DB().AssetGetNext(ai)) + { + if (m_Processor.m_Cursor.m_ID.m_Height < r.pForks[6].m_Height) + ai.SetCid(nullptr); + ser & ai; + } ser & (Asset::s_MaxCount + 1); // terminator diff --git a/node/processor.cpp b/node/processor.cpp index 2f285ae03..114f0121d 100644 --- a/node/processor.cpp +++ b/node/processor.cpp @@ -3245,6 +3245,7 @@ void NodeProcessor::Recognizer::Recognize(const TxKernelAssetCreate& v, Height h evt.m_Info.m_Owner = v.m_Owner; evt.m_Info.m_Value = Zero; evt.m_Info.m_Deposit = Rules::get().get_DepositForCA(h); + evt.m_Info.SetCid(nullptr); AddEvent(h, EventKey::s_IdxKernel + nKrnIdx, evt, key); } @@ -3288,7 +3289,6 @@ void NodeProcessor::Recognizer::Recognize(const TxKernelAssetDestroy& v, Height evt.m_Flags = proto::Event::Flags::Delete; evt.m_EmissionChange = 0; - evt.m_Info.m_Owner = v.m_Owner; evt.m_Info.m_Value = Zero; evt.m_Info.m_Deposit = v.get_Deposit(); @@ -3574,10 +3574,10 @@ bool NodeProcessor::HandleKernelType(const TxKernelAssetCreate& krn, BlockInterp { Asset::ID aid; Amount valDeposit; - return HandleAssetCreate(krn.m_Owner, krn.m_MetaData, bic, aid, valDeposit); + return HandleAssetCreate(krn.m_Owner, nullptr, krn.m_MetaData, bic, aid, valDeposit); } -bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metadata& md, BlockInterpretCtx& bic, Asset::ID& aid, Amount& valDeposit, uint32_t nSubIdx) +bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const ContractID* pCid, const Asset::Metadata& md, BlockInterpretCtx& bic, Asset::ID& aid, Amount& valDeposit, uint32_t nSubIdx) { if (!bic.m_AlreadyValidated) { @@ -3607,7 +3607,7 @@ bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metad ai.m_Owner = pidOwner; ai.m_LockHeight = bic.m_Height; ai.m_Deposit = valDeposit = Rules::get().get_DepositForCA(bic.m_Height); - + ai.SetCid(pCid); ai.m_Metadata.m_Hash = md.m_Hash; { @@ -3627,7 +3627,8 @@ bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metad bufBlob.resize(sizeof(AssetCreateInfoPacked) + md.m_Value.size()); auto* pAcip = reinterpret_cast(&bufBlob.front()); - memcpy(&pAcip->m_Owner, &pidOwner, sizeof(pidOwner)); + pAcip->m_OwnedByContract = !!pCid; + Cast::Down(pAcip->m_Owner) = pAcip->m_OwnedByContract ? (*pCid) : Cast::Down(pidOwner); if (!md.m_Value.empty()) memcpy(pAcip + 1, &md.m_Value.front(), md.m_Value.size()); @@ -3653,13 +3654,13 @@ bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metad bool NodeProcessor::HandleKernelType(const TxKernelAssetDestroy& krn, BlockInterpretCtx& bic) { Amount valDeposit = krn.get_Deposit(); - if (!HandleAssetDestroy(krn.m_Owner, bic, krn.m_AssetID, valDeposit, true)) + if (!HandleAssetDestroy(krn.m_Owner, nullptr, bic, krn.m_AssetID, valDeposit, true)) return false; return true; } -bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx& bic, Asset::ID aid, Amount& valDeposit, bool bDepositCheck, uint32_t nSubIdx) +bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, const ContractID* pCid, BlockInterpretCtx& bic, Asset::ID aid, Amount& valDeposit, bool bDepositCheck, uint32_t nSubIdx) { if (!bic.m_AlreadyValidated) bic.EnsureAssetsUsed(m_DB); @@ -3716,13 +3717,18 @@ bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx { Asset::Full ai; ai.m_ID = aid; - ai.m_Owner = pidOwner; + ai.SetCid(pCid); BlockInterpretCtx::Der der(bic); der & ai.m_Metadata & ai.m_LockHeight; + if (pCid) + ai.m_Metadata.get_Owner(ai.m_Owner, *pCid); + else + ai.m_Owner = pidOwner; + if (bic.m_Height >= Rules::get().pForks[5].m_Height) der & ai.m_Deposit; else @@ -5147,7 +5153,7 @@ bool NodeProcessor::get_HdrAt(Block::SystemState::Full& s) Asset::ID NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetCreate(const Asset::Metadata& md, const PeerID& pidOwner, Amount& valDeposit) { Asset::ID aid = 0; - if (!m_Proc.HandleAssetCreate(pidOwner, md, m_Bic, aid, valDeposit, m_AssetEvtSubIdx)) + if (!m_Proc.HandleAssetCreate(pidOwner, &m_FarCalls.m_Stack.back().m_Cid, md, m_Bic, aid, valDeposit, m_AssetEvtSubIdx)) return 0; BlockInterpretCtx::Ser ser(m_Bic); @@ -5177,14 +5183,16 @@ bool NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetEmit(Asset::ID aid, co bool NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetDestroy(Asset::ID aid, const PeerID& pidOwner, Amount& valDeposit) { - if (!m_Proc.HandleAssetDestroy(pidOwner, m_Bic, aid, valDeposit, false, m_AssetEvtSubIdx)) + const ContractID& cid = m_FarCalls.m_Stack.back().m_Cid; + + if (!m_Proc.HandleAssetDestroy(pidOwner, &cid, m_Bic, aid, valDeposit, false, m_AssetEvtSubIdx)) return false; BlockInterpretCtx::Ser ser(m_Bic); RecoveryTag::Type nTag = RecoveryTag::AssetDestroy; ser & nTag; ser & aid; - ser & pidOwner; + ser & cid; m_AssetEvtSubIdx++; return true; @@ -5213,7 +5221,7 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::UndoVars() Asset::Metadata md; Amount valDeposit; - if (!m_Proc.HandleAssetCreate(pidOwner, md, m_Bic, aid, valDeposit)) + if (!m_Proc.HandleAssetCreate(pidOwner, nullptr, md, m_Bic, aid, valDeposit)) return OnCorrupted(); } break; @@ -5241,11 +5249,12 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::UndoVars() Asset::ID aid = 0; PeerID pidOwner; + ContractID cid; der & aid; - der & pidOwner; + der & cid; Amount valDeposit; - if (!m_Proc.HandleAssetDestroy(pidOwner, m_Bic, aid, valDeposit, false)) + if (!m_Proc.HandleAssetDestroy(pidOwner, &cid, m_Bic, aid, valDeposit, false)) return OnCorrupted(); } break; @@ -6586,11 +6595,13 @@ bool NodeProcessor::EnumKernels(IKrnWalker& wlkKrn, const HeightRange& hr) for (wlkKrn.m_Height = hr.m_Min; wlkKrn.m_Height <= hr.m_Max; wlkKrn.m_Height++) { + uint64_t rowID = FindActiveAtStrict(wlkKrn.m_Height); + txve.m_vKernels.clear(); - ReadKrns(FindActiveAtStrict(wlkKrn.m_Height), txve); + ReadKrns(rowID, txve); wlkKrn.m_nKrnIdx = 0; - if (!wlkKrn.ProcessHeight(txve.m_vKernels)) + if (!wlkKrn.ProcessHeight(rowID, txve.m_vKernels)) return false; if (wlkKrn.m_pLa) @@ -6959,7 +6970,7 @@ void NodeProcessor::RebuildNonStd() ByteBuffer m_Rollback; - virtual bool ProcessHeight(const std::vector& v) override + virtual bool ProcessHeight(uint64_t rowID, const std::vector& v) override { BlockInterpretCtx bic(m_Height, true); m_pBic = &bic; @@ -6974,6 +6985,11 @@ void NodeProcessor::RebuildNonStd() Process(v); bic.m_Rollback.swap(m_Rollback); + + if (m_Height > m_This.m_Extra.m_Fossil) + // replace rollback data + m_This.m_DB.set_StateRB(rowID, m_Rollback); + m_Rollback.clear(); cf.Do(m_This, m_Height); @@ -7029,13 +7045,24 @@ int NodeProcessor::get_AssetAt(Asset::Full& ai, Height h) OnCorrupted(); auto* pAcip = reinterpret_cast(wlk.m_Body.p); - memcpy(&ai.m_Owner, &pAcip->m_Owner, sizeof(ai.m_Owner)); ai.m_Metadata.m_Value.resize(wlk.m_Body.n - sizeof(AssetCreateInfoPacked)); if (!ai.m_Metadata.m_Value.empty()) memcpy(&ai.m_Metadata.m_Value.front(), pAcip + 1, ai.m_Metadata.m_Value.size()); ai.m_Metadata.UpdateHash(); + if (pAcip->m_OwnedByContract) + { + ai.SetCid(&pAcip->m_Owner); + ai.m_Metadata.get_Owner(ai.m_Owner, ai.m_Cid); + } + else + { + ai.SetCid(nullptr); + ai.m_Owner = pAcip->m_Owner; + + } + ai.m_Deposit = Rules::get().get_DepositForCA(wlk.m_Height); typedef std::pair HeightAndIndex; diff --git a/node/processor.h b/node/processor.h index 88acfd3e4..ca03617b1 100644 --- a/node/processor.h +++ b/node/processor.h @@ -173,9 +173,9 @@ class NodeProcessor void InternalAssetAdd(Asset::Full&, bool bMmr); void InternalAssetDel(Asset::ID, bool bMmr); - bool HandleAssetCreate(const PeerID&, const Asset::Metadata&, BlockInterpretCtx&, Asset::ID&, Amount& valDeposit, uint32_t nSubIdx = 0); + bool HandleAssetCreate(const PeerID&, const ContractID*, const Asset::Metadata&, BlockInterpretCtx&, Asset::ID&, Amount& valDeposit, uint32_t nSubIdx = 0); bool HandleAssetEmit(const PeerID&, BlockInterpretCtx&, Asset::ID, AmountSigned, uint32_t nSubIdx = 0); - bool HandleAssetDestroy(const PeerID&, BlockInterpretCtx&, Asset::ID, Amount& valDeposit, bool bDepositCheck, uint32_t nSubIdx = 0); + bool HandleAssetDestroy(const PeerID&, const ContractID*, BlockInterpretCtx&, Asset::ID, Amount& valDeposit, bool bDepositCheck, uint32_t nSubIdx = 0); bool HandleKernel(const TxKernel&, BlockInterpretCtx&); bool HandleKernelTypeAny(const TxKernel&, BlockInterpretCtx&); @@ -435,7 +435,7 @@ class NodeProcessor struct ContractInvokeExtraInfo :public ContractInvokeExtraInfoBase { - ECC::uintBig m_Cid; + ContractID m_Cid; }; bool ExtractBlockWithExtra(Block::Body&, std::vector& vOutsIn, const NodeDB::StateID&, std::vector&); @@ -670,7 +670,7 @@ class NodeProcessor struct IKrnWalker :public TxKernel::IWalker { - virtual bool ProcessHeight(const std::vector& v) { return Process(v); } + virtual bool ProcessHeight(uint64_t rowID, const std::vector& v) { return Process(v); } Height m_Height; LongAction* m_pLa = nullptr; }; @@ -741,6 +741,7 @@ class NodeProcessor struct AssetCreateInfoPacked { PeerID m_Owner; + uint8_t m_OwnedByContract; // followed by metadata }; diff --git a/node/unittests/node_test.cpp b/node/unittests/node_test.cpp index 1e8af2540..5c73a78ce 100644 --- a/node/unittests/node_test.cpp +++ b/node/unittests/node_test.cpp @@ -1770,7 +1770,7 @@ namespace beam PeerID m_Owner; Asset::ID m_ID = 0; // set after successful creation + proof bool m_Recognized = false; - + bool m_ListReceived = false; bool m_EvtCreated = false; bool m_EvtEmitted = false; @@ -2115,6 +2115,23 @@ namespace beam verify_test(m_Assets.m_ID); } + virtual void OnMsg(proto::AssetsListAt&& msg) override + { + verify_test(m_Assets.m_hCreated); + + if (msg.m_Assets.empty()) + return; + + verify_test(1 == msg.m_Assets.size()); + auto& ai = msg.m_Assets.front(); + + verify_test(m_Assets.m_ID == ai.m_ID); + verify_test(ai.m_Metadata.m_Value == m_Assets.m_Metadata.m_Value); + verify_test(ai.m_Metadata.m_Hash == m_Assets.m_Metadata.m_Hash); + + m_Assets.m_ListReceived = true; + } + struct AchievementTester { bool m_AllDone = true; @@ -2145,6 +2162,7 @@ namespace beam t.Test(m_Assets.m_Recognized, "CA output not recognized"); t.Test(m_Assets.m_EvtCreated, "CA creation not recognized by node"); t.Test(m_Assets.m_EvtEmitted, "CA emission not recognized by node"); + t.Test(m_Assets.m_ListReceived, "CA list not received"); t.Test(m_Shielded.m_SpendConfirmed, "Shielded spend not confirmed"); t.Test(m_Shielded.m_EvtAdd, "Shielded Add event didn't arrive"); t.Test(m_Shielded.m_EvtSpend, "Shielded Spend event didn't arrive"); @@ -2189,6 +2207,10 @@ namespace beam proto::GetProofAsset msgOut; msgOut.m_Owner = m_Assets.m_Owner; Send(msgOut); + + proto::GetAssetsListAt msgOut2; + msgOut2.m_Height = MaxHeight; + Send(msgOut2); } proto::BbsMsg msgBbs; @@ -3321,9 +3343,9 @@ namespace beam NetworkStd net(*this); - io::Address addr; - addr.resolve("127.0.0.1"); - addr.port(g_Port); + io::Address addr; + addr.resolve("127.0.0.1"); + addr.port(g_Port); net.m_Cfg.m_vNodes.resize(4, addr); // create several connections, let the compete net.Connect(); @@ -3363,6 +3385,13 @@ namespace beam net.PostRequest(*pHdrs, *this); m_nProofsExpected++; + { + RequestAssetsListAt::Ptr pReq(new RequestAssetsListAt); + pReq->m_Msg.m_Height = MaxHeight; + net.PostRequest(*pReq, *this); + m_nProofsExpected++; + } + SetTimer(90 * 1000); m_bRunning = true; io::Reactor::get_Current().run(); diff --git a/wallet/client/wallet_client.cpp b/wallet/client/wallet_client.cpp index 1e7b8d0f0..c927f2b8b 100644 --- a/wallet/client/wallet_client.cpp +++ b/wallet/client/wallet_client.cpp @@ -150,6 +150,11 @@ struct WalletModelBridge : public Bridge } #endif // BEAM_ASSET_SWAP_SUPPORT + void loadFullAssetsList() override + { + call_async(&IWalletModelAsync::loadFullAssetsList); + } + #ifdef BEAM_ATOMIC_SWAP_SUPPORT void getSwapOffers() override { @@ -1898,6 +1903,28 @@ namespace beam::wallet } #endif // BEAM_ASSET_SWAP_SUPPORT + void WalletClient::loadFullAssetsList() + { + auto wallet = m_wallet.lock(); + if (wallet) + { + wallet->RequestAssetsListAt(MaxHeight, [this](std::vector&& res) + { + std::set assetsFullList{ Asset::s_BeamID }; + for (const auto& ai : res) + { + assetsFullList.insert(ai.m_ID); + } + + postFunctionToClientContext([this, assetsFullList]() + { + m_assetsFullList = std::move(assetsFullList); + onFullAssetsListLoaded(); + }); + }); + } + } + #ifdef BEAM_IPFS_SUPPORT void WalletClient::getIPFSStatus() { @@ -2276,34 +2303,6 @@ namespace beam::wallet return status; } - void WalletClient::loadFullAssetsList() - { - auto wallet = m_wallet.lock(); - if (wallet) - { - auto h = m_status.stateID.m_Height; - wallet->RequestAssetsListAt(h, [this](ByteBuffer assetsBuffer) - { - std::vector assets; - size_t assetsCount = assetsBuffer.size() / sizeof(Asset::ID); - assets.resize(assetsCount); - memcpy(assets.data(), assetsBuffer.data(), assetsBuffer.size()); - - std::set assetsFullList; - for (auto asset : assets) - { - assetsFullList.insert(asset); - getAssetInfo(asset); - } - - postFunctionToClientContext([this, assetsFullList]() - { - m_assetsFullList = assetsFullList; - }); - }); - } - } - void WalletClient::onNodeConnectionFailed(const proto::NodeConnection::DisconnectReason& reason) { // reason -> ErrorType @@ -2361,7 +2360,7 @@ namespace beam::wallet m_unsafeActiveTxCount = count; m_mpLockTimeLimit = limit; }); - loadFullAssetsList(); + auto currentHeight = w->get_TipHeight(); struct Walker :public Block::SystemState::IHistory::IWalker diff --git a/wallet/client/wallet_client.h b/wallet/client/wallet_client.h index 3162e1739..d564b4c37 100644 --- a/wallet/client/wallet_client.h +++ b/wallet/client/wallet_client.h @@ -222,6 +222,7 @@ namespace beam::wallet virtual void onExportTxHistoryToCsv(const std::string& data) {} virtual void onAssetInfo(Asset::ID assetId, const WalletAsset&) {} virtual void onStopped() {} + virtual void onFullAssetsListLoaded() {} #ifdef BEAM_ASSET_SWAP_SUPPORT void onDexOrdersChanged(ChangeAction, const std::vector&) override {} @@ -307,6 +308,8 @@ namespace beam::wallet void cancelDexOrder(const DexOrderID&) override; #endif // BEAM_ASSET_SWAP_SUPPORT + virtual void loadFullAssetsList() override; + #ifdef BEAM_IPFS_SUPPORT void getIPFSStatus() override; #endif @@ -357,7 +360,6 @@ namespace beam::wallet bool OnProgress(uint64_t done, uint64_t total) override; WalletStatus getStatus() const; - void loadFullAssetsList(); void updateStatus(); void updateClientState(const WalletStatus&); void updateMaxPrivacyStats(const WalletStatus& status); @@ -470,6 +472,6 @@ namespace beam::wallet std::unique_ptr m_httpClient; beam::Timestamp m_averageBlockTime = 0; beam::Timestamp m_lastBlockTime = 0; - std::set m_assetsFullList = {Asset::s_BeamID}; + std::set m_assetsFullList = { Asset::s_BeamID }; }; } diff --git a/wallet/client/wallet_model_async.h b/wallet/client/wallet_model_async.h index 02949d5ba..b2f29f5f9 100644 --- a/wallet/client/wallet_model_async.h +++ b/wallet/client/wallet_model_async.h @@ -87,6 +87,7 @@ namespace beam::wallet virtual void publishDexOrder(const DexOrder&) = 0; virtual void cancelDexOrder(const DexOrderID&) = 0; #endif // BEAM_ASSET_SWAP_SUPPORT + virtual void loadFullAssetsList() = 0; #ifdef BEAM_IPFS_SUPPORT virtual void getIPFSStatus() = 0; diff --git a/wallet/core/wallet.cpp b/wallet/core/wallet.cpp index 37aa060f6..5fa00956a 100644 --- a/wallet/core/wallet.cpp +++ b/wallet/core/wallet.cpp @@ -1095,29 +1095,7 @@ namespace beam::wallet { const auto& info = req.m_Res.m_Info; const auto height = sTip.m_Height; - - m_WalletDB->saveAsset(info, height); - LOG_INFO() << msgPrefix << (msgPrefix.empty() ? "" : " ") << "Received proof for Asset with ID " << info.m_ID; - - if (Key::IKdf::Ptr maserKdf = m_WalletDB->get_MasterKdf()) - { - std::string strMeta; - info.m_Metadata.get_String(strMeta); - - if (beam::wallet::GetAssetOwnerID(maserKdf, strMeta) == info.m_Owner) - { - m_WalletDB->markAssetOwned(info.m_ID); - } - } - else - { - LOG_WARNING() << msgPrefix << "Unable to get master key. Asset's " << req.m_Res.m_Info.m_ID << " ownership won't be checked."; - } - - if(const auto wasset = m_WalletDB->findAsset(info.m_ID)) - { - wasset->LogInfo(msgPrefix); - } + ProcessAssetInfo(info, height, msgPrefix); if (tx) { @@ -1165,6 +1143,32 @@ namespace beam::wallet } } + void Wallet::ProcessAssetInfo(const Asset::Full& info, Height height, const std::string& logPrefix) + { + m_WalletDB->saveAsset(info, height); + LOG_INFO() << logPrefix << (logPrefix.empty() ? "" : " ") << "Received proof for Asset with ID " << info.m_ID; + + if (Key::IKdf::Ptr maserKdf = m_WalletDB->get_MasterKdf()) + { + std::string strMeta; + info.m_Metadata.get_String(strMeta); + + if (beam::wallet::GetAssetOwnerID(maserKdf, strMeta) == info.m_Owner) + { + m_WalletDB->markAssetOwned(info.m_ID); + } + } + else + { + LOG_WARNING() << logPrefix << "Unable to get master key. Asset's " << info.m_ID << " ownership won't be checked."; + } + + if (const auto wasset = m_WalletDB->findAsset(info.m_ID)) + { + wasset->LogInfo(logPrefix); + } + } + void Wallet::OnRequestComplete(MyRequestKernel2& r) { auto it = m_ActiveTransactions.find(r.m_TxID); @@ -1214,7 +1218,11 @@ namespace beam::wallet void Wallet::OnRequestComplete(MyRequestAssetsListAt& r) { - r.m_callback(r.m_Res.m_AssetsList); + for (const auto& ai : r.m_Res) + { + ProcessAssetInfo(ai, 0, ""); + } + r.m_callback(std::move(r.m_Res)); } struct Wallet::RecognizerHandler : NodeProcessor::Recognizer::IHandler @@ -2364,8 +2372,12 @@ namespace beam::wallet PostReqUnique(*pVal); } - void Wallet::RequestAssetsListAt(Height h, std::function&& onRequestComplete) + void Wallet::RequestAssetsListAt(Height h, std::function&&)>&& onRequestComplete) { + if (!m_PendingAssetsListAt.empty()) + { + DeleteReq(*m_PendingAssetsListAt.begin()); + } MyRequestAssetsListAt::Ptr pVal(new MyRequestAssetsListAt); pVal->m_Msg.m_Height = h; pVal->m_callback = std::move(onRequestComplete); diff --git a/wallet/core/wallet.h b/wallet/core/wallet.h index c50a2d78e..28f0ee4bf 100644 --- a/wallet/core/wallet.h +++ b/wallet/core/wallet.h @@ -177,7 +177,7 @@ namespace beam::wallet void RequestVouchersFrom(const WalletID& peerID, const WalletID& myID, uint32_t nCount = 1); virtual void OnVouchersFrom(const WalletAddress&, const WalletID& myID, std::vector&&); void RequestShieldedOutputsAt(Height h, std::function&& onRequestComplete); - void RequestAssetsListAt(Height h, std::function&& onRequestComplete); + void RequestAssetsListAt(Height h, std::function&&)>&& onRequestComplete); bool IsConnectedToOwnNode() const; bool CanDetectCoins() const; void EnableBodyRequests(bool value); @@ -267,6 +267,7 @@ namespace beam::wallet Height GetEventsHeightNext() const; void ProcessEventShieldedUtxo(const proto::Event::Shielded& shieldedEvt, Height h); void RequestStateSummary(); + void ProcessAssetInfo(const Asset::Full& info, Height height, const std::string& logPrefix); void OnTransactionMsg(const WalletID& myID, const SetTxParameter& msg); BaseTransaction::Ptr ConstructTransaction(const TxID& id, TxType type); @@ -363,7 +364,7 @@ namespace beam::wallet struct AssetsListAt { - std::function m_callback; + std::function&&)> m_callback; }; };