diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 99f7660b2..179dd7524 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-10.15, ubuntu-18.04, windows-2019] + # os: [macos-11] + os: [macos-11, ubuntu-18.04, windows-2019] steps: - uses: actions/checkout@v2 @@ -30,8 +31,8 @@ jobs: # Create Build Environment ############################################################################### - - name: Create Build Environment [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Create Build Environment [macos-11] + if: matrix.os == 'macos-11' run: | echo $GITHUB_WORKSPACE echo "OPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1" >> $GITHUB_ENV @@ -63,18 +64,26 @@ jobs: echo "BOOST_ROOT=c:\boost_prebuild" >> $GITHUB_ENV - name: Download boost [ubuntu && macos] - if: matrix.os != 'windows-2019' + if: matrix.os != 'windows-2019' && matrix.os != 'macos-11' shell: bash run: | git clone --depth=1 https://github.com/BeamMW/boost_prebuild_${{matrix.os}}.git ${{runner.workspace}}/boost_prebuild echo "BOOST_INCLUDEDIR=${{runner.workspace}}/boost_prebuild/include" >> $GITHUB_ENV echo "BOOST_LIBRARYDIR=${{runner.workspace}}/boost_prebuild/lib/" >> $GITHUB_ENV + - name: Download boost [macos] + if: matrix.os == 'macos-11' + shell: bash + run: | + git clone --depth=1 https://github.com/BeamMW/boost_prebuild_macos-10.15.git ${{runner.workspace}}/boost_prebuild + echo "BOOST_INCLUDEDIR=${{runner.workspace}}/boost_prebuild/include" >> $GITHUB_ENV + echo "BOOST_LIBRARYDIR=${{runner.workspace}}/boost_prebuild/lib/" >> $GITHUB_ENV + ############################################################################### # Configure CMake ############################################################################### - - name: Configure CMake [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Configure CMake [macos-11] + if: matrix.os == 'macos-11' run: | # git apply 3rdparty/protobuf-patch.diff cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DDEBUG_MESSAGES_IN_RELEASE_MODE=On -DBEAM_LINK_TYPE=Static -DBRANCH_NAME=${GITHUB_REF##*/} -DBEAM_HW_WALLET=Off . @@ -103,8 +112,8 @@ jobs: ############################################################################### # Build ############################################################################### - - name: Build [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Build [macos-11] + if: matrix.os == 'macos-11' run: cmake --build . --parallel --config $BUILD_TYPE - name: Build [ununtu all] @@ -120,8 +129,8 @@ jobs: ############################################################################### # Test ############################################################################### - - name: Test [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Test [macos-11] + if: matrix.os == 'macos-11' continue-on-error: false run: ctest -C $BUILD_TYPE --verbose @@ -140,14 +149,14 @@ jobs: ############################################################################### # Collect artifacts ############################################################################### - - name: Import Code-Signing Certificates [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Import Code-Signing Certificates [macos-11] + if: matrix.os == 'macos-11' uses: Apple-Actions/import-codesign-certs@v1 with: p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} - - name: Sign the mac binaries [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Sign the mac binaries [macos-11] + if: matrix.os == 'macos-11' run: | codesign --deep --force -v -s "${{secrets.MACOS_SIGN_IDENTITY}}" -o runtime --timestamp beam/beam-node${{env.BEAM_TARGET_SUFFIX}} codesign --deep --force -v -s "${{secrets.MACOS_SIGN_IDENTITY}}" -o runtime --timestamp wallet/cli/beam-wallet${{env.BEAM_TARGET_SUFFIX}} @@ -166,8 +175,8 @@ jobs: sha256sum wallet/broadcaster/broadcaster${{env.BEAM_TARGET_SUFFIX}} > wallet/broadcaster/broadcaster${{env.BEAM_TARGET_SUFFIX}}-checksum.txt sha256sum bvm/ethash_service/ethash-service > bvm/ethash_service/ethash-service-checksum.txt - - name: Checksum [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: Checksum [macos-11] + if: matrix.os == 'macos-11' run: | shasum -a 256 beam/beam-node${{env.BEAM_TARGET_SUFFIX}} > beam/beam-node${{env.BEAM_TARGET_SUFFIX}}-checksum.txt shasum -a 256 wallet/cli/beam-wallet${{env.BEAM_TARGET_SUFFIX}} > wallet/cli/beam-wallet${{env.BEAM_TARGET_SUFFIX}}-checksum.txt @@ -176,7 +185,7 @@ jobs: shasum -a 256 wallet/broadcaster/broadcaster${{env.BEAM_TARGET_SUFFIX}} > wallet/broadcaster/broadcaster${{env.BEAM_TARGET_SUFFIX}}-checksum.txt shasum -a 256 bvm/ethash_service/ethash-service > bvm/ethash_service/ethash-service-checksum.txt - - name: Collect [macos-10.15 && ununtu all] + - name: Collect [macos-11 && ununtu all] shell: bash if: matrix.os != 'windows-2019' run: | @@ -228,8 +237,8 @@ jobs: certUtil -hashfile artifacts/ethash-service.exe SHA256 > artifacts/ethash-service-checksum.txt certUtil -hashfile artifacts/ipfs-bindings.dll SHA256 > artifacts/ipfs-bindings-checksum.txt - - name: OS name [macos-10.15] - if: matrix.os == 'macos-10.15' + - name: OS name [macos-11] + if: matrix.os == 'macos-11' run: echo "PLATFORM_NAME=mac" >> $GITHUB_ENV - name: OS name [ununtu all] @@ -297,7 +306,7 @@ jobs: # Build IOS ############################################################################### build_ios: - runs-on: macos-10.15 + runs-on: macos-11 #if: ${{false}} steps: @@ -394,7 +403,7 @@ jobs: abi: [x86, x86_64, armeabi-v7a, arm64-v8a] env: ANDROID_ABI: ${{matrix.abi}} - ANDROID_SDK_VERSION: 23 + ANDROID_SDK_VERSION: 25 steps: - uses: actions/checkout@v2 @@ -408,7 +417,8 @@ jobs: run: | git clone --depth=1 https://github.com/BeamMW/boost-android.git ${{runner.workspace}}/dependencies/boost_1_68-android git clone --depth=1 https://github.com/BeamMW/openssl-android.git ${{runner.workspace}}/dependencies/Prebuilt-OpenSSL-Android - echo "ANDROID_NDK_HOME=/usr/local/lib/android/sdk/ndk-bundle" >> $GITHUB_ENV + echo "ANDROID_NDK_HOME=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV + ls /usr/local/lib/android/sdk echo "BOOST_ROOT_ANDROID=${{runner.workspace}}/dependencies/boost_1_68-android" >> $GITHUB_ENV echo "OPENSSL_ROOT_DIR_ANDROID=${{runner.workspace}}/dependencies/Prebuilt-OpenSSL-Android" >> $GITHUB_ENV diff --git a/CMakeLists.txt b/CMakeLists.txt index 223ec2137..d1c773531 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) cmake_policy(SET CMP0074 NEW) set(VERSION_MAJOR 7) -set(VERSION_MINOR 0 ) +set(VERSION_MINOR 1 ) set(VERSION_REVISION 0) set(GIT_COMMIT_HASH "unknown") diff --git a/android/dao/web_api_creator.cpp b/android/dao/web_api_creator.cpp index d1da15240..466ebbc83 100644 --- a/android/dao/web_api_creator.cpp +++ b/android/dao/web_api_creator.cpp @@ -37,7 +37,7 @@ void WebAPICreator::createApi(WalletModel::Ptr walletModel, const std::string& v const auto appid = beam::wallet::GenerateAppID(appName, appUrl); auto guard = this; - AppsApiUI::ClientThread_Create(walletModel.get(), version, appid, appName, false, + AppsApiUI::ClientThread_Create(walletModel.get(), version, appid, appName, 0, false, [this, guard, version, appName, appid] (AppsApiUI::Ptr api) { if (guard) { diff --git a/bvm/ManagerStd.cpp b/bvm/ManagerStd.cpp index 1ec562c0f..0acecfc1b 100644 --- a/bvm/ManagerStd.cpp +++ b/bvm/ManagerStd.cpp @@ -23,12 +23,19 @@ namespace bvm2 { m_pOut = &m_Out; } - void ManagerStd::Unfreeze() + + bool ManagerStd::IsSuspended() { - assert(m_Freeze); - if (!--m_Freeze) - m_UnfreezeEvt.start(); - //OnUnfreezed(); + return m_Pending.m_pBlocker != nullptr; + } + + void ManagerStd::Pending::OnDone(IBase& x) + { + if (&x == m_pBlocker) + { + m_pBlocker = nullptr; + get_ParentObj().m_UnfreezeEvt.start(); + } } void ManagerStd::OnUnfreezed() @@ -47,53 +54,67 @@ namespace bvm2 { get_ParentObj().OnUnfreezed(); } + void ManagerStd::SetParentContext(std::unique_ptr& pTrg) const + { + assert(!pTrg); + if (m_Context.m_pParent) + pTrg = std::make_unique(*m_Context.m_pParent); + } struct ManagerStd::RemoteRead { - static void SetContext(std::unique_ptr& pTrg, const std::unique_ptr& pSrc) - { - assert(!pTrg); - if (pSrc) - pTrg = std::make_unique(*pSrc); - } - - struct Base - :public proto::FlyClient::Request::IHandler + struct Handler + :public Pending::IBase + ,public proto::FlyClient::Request::IHandler { - ManagerStd* m_pThis; + ManagerStd& m_This; proto::FlyClient::Request::Ptr m_pRequest; - ~Base() { Abort(); } - - void Post() + Handler(ManagerStd& x) + :m_This(x) { - assert(m_pRequest); - Wasm::Test(m_pThis->m_pNetwork != nullptr); - - m_pThis->m_Freeze++; - m_pThis->m_pNetwork->PostRequest(*m_pRequest, *this); } - void Abort() + ~Handler() { - if (m_pRequest) { + if (m_pRequest) + { m_pRequest->m_pTrg = nullptr; m_pRequest.reset(); } } + void Post() + { + assert(m_pRequest); + Wasm::Test(m_This.m_pNetwork != nullptr); + m_This.m_pNetwork->PostRequest(*m_pRequest, *this); + } + + bool CheckDone() + { + if (!m_pRequest->m_pTrg) + return true; + + m_This.m_Pending.m_pBlocker = this; + return false; + } + virtual void OnComplete(proto::FlyClient::Request&) { - assert(m_pRequest && m_pRequest->m_pTrg); - m_pThis->Unfreeze(); + assert(m_pRequest && (this == m_pRequest->m_pTrg)); + m_pRequest->m_pTrg = nullptr; + m_This.m_Pending.OnDone(*this); } }; struct Vars - :public Base + :public Handler ,public IReadVars { - size_t m_Consumed; + using Handler::Handler; + + size_t m_Consumed = 0; ByteBuffer m_Buf; virtual bool MoveNext() override @@ -101,18 +122,18 @@ namespace bvm2 { assert(m_pRequest); auto& r = Cast::Up(*m_pRequest); - if (r.m_pTrg) + if (m_Consumed == m_Buf.size()) { - r.m_pTrg = nullptr; + if (!CheckDone()) + return false; + + if (r.m_Res.m_Result.empty()) + return false; + m_Consumed = 0; m_Buf = std::move(r.m_Res.m_Result); - if (m_Buf.empty()) - r.m_Res.m_bMore = false; } - if (m_Consumed == m_Buf.size()) - return false; - auto* pBuf = &m_Buf.front(); Deserializer der; @@ -151,10 +172,12 @@ namespace bvm2 { struct Logs - :public Base + :public Handler ,public IReadLogs { - size_t m_Consumed; + using Handler::Handler; + + size_t m_Consumed = 0; ByteBuffer m_Buf; virtual bool MoveNext() override @@ -162,18 +185,17 @@ namespace bvm2 { assert(m_pRequest); auto& r = Cast::Up(*m_pRequest); - if (r.m_pTrg) + if (m_Consumed == m_Buf.size()) { - r.m_pTrg = nullptr; + if (!CheckDone()) + return false; + if (r.m_Res.m_Result.empty()) + return false; + m_Consumed = 0; m_Buf = std::move(r.m_Res.m_Result); - if (m_Buf.empty()) - r.m_Res.m_bMore = false; } - if (m_Consumed == m_Buf.size()) - return false; - auto* pBuf = &m_Buf.front(); Deserializer der; @@ -220,11 +242,31 @@ namespace bvm2 { }; + void ManagerStd::PerformSingleRequest(proto::FlyClient::Request& r) + { + auto p = std::make_unique(*this); + p->m_pRequest = &r; + p->Post(); + + p->CheckDone(); + m_Pending.m_pSingleRequest = std::move(p); + } + + proto::FlyClient::Request::Ptr ManagerStd::GetResSingleRequest() + { + assert(m_Pending.m_pSingleRequest); + auto& h = Cast::Up(*m_Pending.m_pSingleRequest); + + assert(h.m_pRequest); + auto pRet = h.m_pRequest; // for more safety don't use std::move(), let the Handler cancel the Request if it's still pending (though that shouldn't happen) + + m_Pending.m_pSingleRequest.reset(); + return pRet; + } void ManagerStd::VarsEnum(const Blob& kMin, const Blob& kMax, IReadVars::Ptr& pOut) { - auto p = std::make_unique(); - p->m_pThis = this; + auto p = std::make_unique(*this); boost::intrusive_ptr pReq(new proto::FlyClient::RequestContractVars); auto& r = *pReq; @@ -232,7 +274,7 @@ namespace bvm2 { kMin.Export(r.m_Msg.m_KeyMin); kMax.Export(r.m_Msg.m_KeyMax); - RemoteRead::SetContext(r.m_pCtx, m_Context.m_pParent); + SetParentContext(r.m_pCtx); p->m_pRequest = std::move(pReq); p->Post(); @@ -241,8 +283,7 @@ namespace bvm2 { void ManagerStd::LogsEnum(const Blob& kMin, const Blob& kMax, const HeightPos* pPosMin, const HeightPos* pPosMax, IReadLogs::Ptr& pOut) { - auto p = std::make_unique(); - p->m_pThis = this; + auto p = std::make_unique(*this); boost::intrusive_ptr pReq(new proto::FlyClient::RequestContractLogs); auto& r = *pReq; @@ -258,7 +299,7 @@ namespace bvm2 { else r.m_Msg.m_PosMax.m_Height = MaxHeight; - RemoteRead::SetContext(r.m_pCtx, m_Context.m_pParent); + SetParentContext(r.m_pCtx); p->m_pRequest = std::move(pReq); p->Post(); @@ -268,116 +309,119 @@ namespace bvm2 { void ManagerStd::SelectContext(bool bDependent, uint32_t /* nChargeNeeded */) { - if (m_EnforceDependent) - bDependent = true; - - proto::FlyClient::RequestEnsureSync::Ptr pReq(new proto::FlyClient::RequestEnsureSync); - pReq->m_IsDependent = bDependent; - Wasm::Test(PerformRequestSync(*pReq)); - - Wasm::Test(m_pHist); + if (!m_Pending.m_pSingleRequest) + { + if (m_EnforceDependent) + bDependent = true; - Block::SystemState::Full s; - m_pHist->get_Tip(s); // zero-inits if no tip + proto::FlyClient::RequestEnsureSync::Ptr pReq(new proto::FlyClient::RequestEnsureSync); + pReq->m_IsDependent = bDependent; - m_Context.m_Height = s.m_Height; + PerformSingleRequest(*pReq); + } - if (bDependent) + if (!IsSuspended()) { - uint32_t n = 0; - const auto* pV = m_pNetwork->get_DependentState(n); - const auto& hvCtx = n ? pV[n - 1] : s.m_Prev; - m_Context.m_pParent = std::make_unique(hvCtx); - } - } + auto pReq = GetResSingleRequest(); + auto& r = pReq->As(); - bool ManagerStd::PerformRequestSync(proto::FlyClient::Request& r) - { - Wasm::Test(m_pNetwork != nullptr); + Wasm::Test(m_pHist); - struct MyHandler - :public proto::FlyClient::Request::IHandler - { - proto::FlyClient::Request* m_pReq = nullptr; + Block::SystemState::Full s; + m_pHist->get_Tip(s); // zero-inits if no tip - ~MyHandler() { - m_pReq->m_pTrg = nullptr; - } + m_Context.m_Height = s.m_Height; - virtual void OnComplete(proto::FlyClient::Request&) override + if (r.m_IsDependent) { - m_pReq->m_pTrg = nullptr; - io::Reactor::get_Current().stop(); + uint32_t n = 0; + const auto* pV = m_pNetwork->get_DependentState(n); + const auto& hvCtx = n ? pV[n - 1] : s.m_Prev; + m_Context.m_pParent = std::make_unique(hvCtx); } - - } myHandler; - - myHandler.m_pReq = &r; - m_pNetwork->PostRequest(r, myHandler); - - io::Reactor::get_Current().run(); - - if (!r.m_pTrg) - return true; - - // propagate the stop - io::Reactor::get_Current().stop(); - return false; + } } bool ManagerStd::get_HdrAt(Block::SystemState::Full& s) { - Wasm::Test(m_pHist); + if (!m_Pending.m_pSingleRequest) + { + Wasm::Test(m_pHist); - Height h = s.m_Height; - if (m_pHist->get_At(s, h)) - return true; + Height h = s.m_Height; + if (m_pHist->get_At(s, h)) + return true; - proto::FlyClient::RequestEnumHdrs::Ptr pReq(new proto::FlyClient::RequestEnumHdrs); - auto& r = *pReq; - r.m_Msg.m_Height = h; + proto::FlyClient::RequestEnumHdrs::Ptr pReq(new proto::FlyClient::RequestEnumHdrs); + pReq->m_Msg.m_Height = h; - if (!PerformRequestSync(r)) - return false; + PerformSingleRequest(*pReq); + } + + if (!IsSuspended()) + { + auto pReq = GetResSingleRequest(); + auto& r = pReq->As(); - if (1 != r.m_vStates.size()) - return false; + if (1 == r.m_vStates.size()) + { + s = std::move(r.m_vStates.front()); + return true; + } + } - s = std::move(r.m_vStates.front()); - return true; + return false; } bool ManagerStd::VarGetProof(Blob& key, ByteBuffer& val, beam::Merkle::Proof& proof) { - proto::FlyClient::RequestContractVar::Ptr pReq(new proto::FlyClient::RequestContractVar); - auto& r = *pReq; - key.Export(r.m_Msg.m_Key); + if (!m_Pending.m_pSingleRequest) + { + proto::FlyClient::RequestContractVar::Ptr pReq(new proto::FlyClient::RequestContractVar); + key.Export(pReq->m_Msg.m_Key); - if (!PerformRequestSync(r)) - return false; + PerformSingleRequest(*pReq); + } - if (r.m_Res.m_Proof.empty()) - return false; + if (!IsSuspended()) + { + auto pReq = GetResSingleRequest(); + auto& r = pReq->As(); - r.m_Res.m_Value.swap(val); - r.m_Res.m_Proof.swap(proof); - return true; + if (!r.m_Res.m_Proof.empty()) + { + r.m_Res.m_Value.swap(val); + r.m_Res.m_Proof.swap(proof); + return true; + } + } + + return false; } bool ManagerStd::LogGetProof(const HeightPos& hp, beam::Merkle::Proof& proof) { - proto::FlyClient::RequestContractLogProof::Ptr pReq(new proto::FlyClient::RequestContractLogProof); - auto& r = *pReq; - r.m_Msg.m_Pos = hp; + if (!m_Pending.m_pSingleRequest) + { + proto::FlyClient::RequestContractLogProof::Ptr pReq(new proto::FlyClient::RequestContractLogProof); + pReq->m_Msg.m_Pos = hp; - if (!PerformRequestSync(r)) - return false; + PerformSingleRequest(*pReq); + } - if (r.m_Res.m_Proof.empty()) - return false; + if (!IsSuspended()) + { + auto pReq = GetResSingleRequest(); + auto& r = pReq->As(); - r.m_Res.m_Proof.swap(proof); - return true; + if (!r.m_Res.m_Proof.empty()) + { + r.m_Res.m_Proof.swap(proof); + return true; + } + } + + return false; } void ManagerStd::OnReset() @@ -393,8 +437,11 @@ namespace bvm2 { m_mapReadVars.Clear(); m_mapReadLogs.Clear(); - m_Freeze = 0; - m_WaitingMsg = false; + m_UnfreezeEvt.cancel(); + + m_Pending.m_pSingleRequest.reset(); + m_Pending.m_pCommMsg.reset(); + m_Pending.m_pBlocker = nullptr; } void ManagerStd::StartRun(uint32_t iMethod) @@ -418,20 +465,24 @@ namespace bvm2 { { assert(m_Comms.m_Rcv.empty()); - if (m_WaitingMsg) - return; // shouldn't happen, but anyway + struct PendingCommMsg + :public Pending::IBase + { + virtual ~PendingCommMsg() {} // auto + io::Timer::Ptr m_pTimer; + }; - m_Freeze++; - m_WaitingMsg = true; + auto p = std::make_unique(); if (static_cast(-1) != nTimeout_ms) { - if (!m_pOnMsgTimer) - m_pOnMsgTimer = io::Timer::create(io::Reactor::get_Current()); - - m_pOnMsgTimer->start(nTimeout_ms, false, [this]() { Comm_OnNewMsg(); }); + p->m_pTimer = io::Timer::create(io::Reactor::get_Current()); + p->m_pTimer->start(nTimeout_ms, false, [this]() { Comm_OnNewMsg(); }); } + m_Pending.m_pCommMsg = std::move(p); + m_Pending.m_pBlocker = m_Pending.m_pCommMsg.get(); + } void ManagerStd::Comm_OnNewMsg(const Blob& msg, Comm::Channel& c) @@ -452,13 +503,10 @@ namespace bvm2 { void ManagerStd::Comm_OnNewMsg() { - if (m_WaitingMsg) + if (m_Pending.m_pCommMsg) { - m_WaitingMsg = false; - Unfreeze(); - - if (m_pOnMsgTimer) - m_pOnMsgTimer->cancel(); + m_Pending.OnDone(*m_Pending.m_pCommMsg); + m_Pending.m_pCommMsg.reset(); } } @@ -466,7 +514,7 @@ namespace bvm2 { { while (!IsDone()) { - if (m_Freeze) + if (IsSuspended()) return; RunOnce(); diff --git a/bvm/ManagerStd.h b/bvm/ManagerStd.h index 9d021b0a0..c824879b2 100644 --- a/bvm/ManagerStd.h +++ b/bvm/ManagerStd.h @@ -22,9 +22,25 @@ namespace beam::bvm2 { :public ProcessorManager { protected: - uint32_t m_Freeze = 0; // incremented when we're awaiting something - bool m_WaitingMsg; - void Unfreeze(); + + struct Pending + { + struct IBase + { + virtual ~IBase() {} + typedef std::unique_ptr Ptr; + }; + + IBase* m_pBlocker = nullptr; + + IBase::Ptr m_pSingleRequest; + IBase::Ptr m_pCommMsg; + + void OnDone(IBase&); + + IMPLEMENT_GET_PARENT_OBJ(ManagerStd, m_Pending) + } m_Pending; + void OnUnfreezed(); struct UnfreezeEvt @@ -36,13 +52,14 @@ namespace beam::bvm2 { struct RemoteRead; + void SetParentContext(std::unique_ptr& pTrg) const; + void PerformSingleRequest(proto::FlyClient::Request& r); + proto::FlyClient::Request::Ptr GetResSingleRequest(); + void RunSync(); - bool PerformRequestSync(proto::FlyClient::Request&); void Comm_OnNewMsg(const Blob&, Comm::Channel&); void Comm_OnNewMsg(); - io::Timer::Ptr m_pOnMsgTimer; - protected: void SelectContext(bool bDependent, uint32_t nChargeNeeded) override; bool get_HdrAt(Block::SystemState::Full&) override; @@ -56,6 +73,7 @@ namespace beam::bvm2 { virtual void OnDone(const std::exception* pExc) {} virtual void OnReset(); + virtual bool IsSuspended() override; public: diff --git a/bvm/bvm2.cpp b/bvm/bvm2.cpp index 2b79303c4..7b589de53 100644 --- a/bvm/bvm2.cpp +++ b/bvm/bvm2.cpp @@ -186,9 +186,9 @@ namespace bvm2 { InitBase(Limits::StackSize + nStackBytes); } - void ProcessorManager::InitMem() + void ProcessorManager::InitMem(uint32_t nStackBytesExtra /* = 0 */) { - InitBase(0x20000); // 128K + InitBase(0x20000 + nStackBytesExtra); // 128K ZeroObject(m_AuxAlloc); m_NeedComma = false; @@ -216,7 +216,7 @@ namespace bvm2 { return hdr; } - void ProcessorContract::CallFar(const ContractID& cid, uint32_t iMethod, Wasm::Word pArgs, uint8_t bInheritContext) + void ProcessorContract::CallFar(const ContractID& cid, uint32_t iMethod, Wasm::Word pArgs, uint32_t nArgs, uint8_t bInheritContext) { struct MyCheckpoint :public Wasm::Checkpoint { @@ -574,7 +574,9 @@ namespace bvm2 { template struct Caller { template static void Call(TProcessor& me, const TArgs& args) { - me.m_Stack.template Push(args.Call(me)); + auto ret = args.Call(me); + if (!me.IsSuspended()) + me.m_Stack.template Push(ret); } }; template <> struct Caller { @@ -669,6 +671,26 @@ namespace bvm2 { return x; } + // test there're no collisions + void NeverCalled_VerifyNoIdCollisions(uint32_t nBinding) + { +#define THE_MACRO(id, ret, name) case id: + + // must ensure no ID collisions within Common, Contract, Manager, and also combined {Common, Contract} and {Common, Manager} + // It's not necessary that {Common, Contract, Manager} all be unique (we can assign same ID to a method in Contract and other method in Manager), but we prefer to avoid this too + // This is to ease in the future the promotion of a method from Contract/Manager into Common + + switch (nBinding) + { + BVMOpsAll_Common(THE_MACRO) + BVMOpsAll_Contract(THE_MACRO) + BVMOpsAll_Manager(THE_MACRO) + break; + } + +#undef THE_MACRO + } + #define PAR_PASS(type, name) m_##name.V #define PAR_DECL(type, name) ParamWrap m_##name; #define PAR_ASSIGN(type, name) args.m_##name = @@ -1365,7 +1387,7 @@ namespace bvm2 { } auto nDepth = m_FarCalls.m_Stack.size(); // see if depth increases. If it doesn't - the call was hijacked, performed natively. No need to adjust m_BytesMax - CallFar(get_AddrAsR(cid), iMethod, pArgs, bInheritContext); + CallFar(get_AddrAsR(cid), iMethod, pArgs, nArgs, bInheritContext); if (!bInheritContext && (m_FarCalls.m_Stack.size() > nDepth)) m_Stack.m_BytesMax = nCalleeStackMax; @@ -1502,10 +1524,11 @@ namespace bvm2 { AssetVar av; get_AssetOwner(av.m_Owner, m_FarCalls.m_Stack.back().m_Cid, md); - Asset::ID ret = AssetCreate(md, av.m_Owner); + Amount valDeposit; + Asset::ID ret = AssetCreate(md, av.m_Owner, valDeposit); if (ret) { - ProcessorPlus_Contract::From(*this).HandleAmountOuter(Rules::get().CA.DepositForList, Zero, true); + ProcessorPlus_Contract::From(*this).HandleAmountOuter(valDeposit, Zero, true); SetAssetKey(av, ret); SaveVar(av.m_vk.ToBlob(), av.m_Owner); @@ -1562,10 +1585,11 @@ namespace bvm2 { AssetVar av; get_AssetStrict(av, aid); - bool b = AssetDestroy(aid, av.m_Owner); + Amount valDeposit; + bool b = AssetDestroy(aid, av.m_Owner, valDeposit); if (b) { - HandleAmountOuter(Rules::get().CA.DepositForList, Zero, false); + HandleAmountOuter(valDeposit, Zero, false); SaveVar(av.m_vk.ToBlob(), Blob(nullptr, 0)); } @@ -1638,6 +1662,17 @@ namespace bvm2 { return r.pForks[iFork].m_Height; } + BVM_METHOD(get_ForkHeight) + { + if (Kind::Contract == get_Kind()) + Wasm::Test(IsPastFork(5)); + + const Rules& r = Rules::get(); + return (iFork >= _countof(r.pForks)) ? MaxHeight : r.pForks[iFork].m_Height; + } + + BVM_METHOD_HOST_AUTO(get_ForkHeight) + struct Processor::DataProcessor::Instance { template @@ -2325,7 +2360,8 @@ namespace bvm2 { } BVM_METHOD_HOST(Vars_Enum) { - EnsureContext(); + if (!EnsureContext()) + return 0; IReadVars::Ptr pObj; VarsEnum(Blob(pKey0, nKey0), Blob(pKey1, nKey1), pObj); @@ -2404,7 +2440,8 @@ namespace bvm2 { } BVM_METHOD_HOST(Logs_Enum) { - EnsureContext(); + if (!EnsureContext()) + return 0; IReadLogs::Ptr pObj; LogsEnum(Blob(pKey0, nKey0), Blob(pKey1, nKey1), pPosMin, pPosMax, pObj); @@ -2468,7 +2505,8 @@ namespace bvm2 { uint32_t ProcessorManager::VarGetProofInternal(const void* pKey, uint32_t nKey, Wasm::Word& pVal, Wasm::Word& nVal, Wasm::Word& pProof) { - EnsureContext(); + if (!EnsureContext()) + return 0; ByteBuffer val; beam::Merkle::Proof proof; @@ -2531,7 +2569,8 @@ namespace bvm2 { uint32_t ProcessorManager::LogGetProofInternal(const HeightPos& hp, Wasm::Word& pProof) { - EnsureContext(); + if (!EnsureContext()) + return 0; ByteBuffer val; beam::Merkle::Proof proof; @@ -2937,11 +2976,9 @@ namespace bvm2 { void ProcessorManager::DocQuotedText(const char* sz) { - if (!m_RawText) - *m_pOut << '"'; + *m_pOut << '"'; DocEncodedText(sz); - if (!m_RawText) - *m_pOut << '"'; + *m_pOut << '"'; } void ProcessorManager::DocEncodedText(const char* sz) @@ -2979,10 +3016,7 @@ namespace bvm2 { void ProcessorManager::DocOnNext() { if (m_NeedComma) - { - if (!m_RawText) - *m_pOut << ','; - } + *m_pOut << ','; else m_NeedComma = true; } @@ -3000,6 +3034,9 @@ namespace bvm2 { BVM_METHOD(GenerateKernel) { + if (!EnsureContext()) + return; + #pragma pack (push, 1) struct SigRequest { Wasm::Word m_pID; @@ -3025,6 +3062,9 @@ namespace bvm2 { } BVM_METHOD_HOST(GenerateKernel) { + if (!EnsureContext()) + return; + auto& v = GenerateKernel(pCid, iMethod, Blob(pArg, nArg), pFunds, nFunds, false, szComment, nCharge); v.m_vSig.reserve(nSig); @@ -3036,19 +3076,53 @@ namespace bvm2 { } } + BVM_METHOD(GetApiVersion) + { + return Shaders::ApiVersion::Current; + } + + BVM_METHOD_HOST_AUTO(GetApiVersion) + + BVM_METHOD(SetApiVersion) + { + Wasm::Test(Shaders::ApiVersion::Current == nVer); + } + + BVM_METHOD_HOST_AUTO(SetApiVersion) + + void ProcessorManager::RunOnce() + { + assert(!IsSuspended()); + auto nIp = get_Ip(); + auto nSp = m_Stack.m_Pos; + + Processor::RunOnce(); + + if (IsSuspended()) + { + Jmp(nIp); // restore + m_Stack.m_Pos = nSp; + } + } + Height ProcessorManager::get_Height() { EnsureContext(); return m_Context.m_Height; } - void ProcessorManager::EnsureContext() + bool ProcessorManager::EnsureContext() { - if (MaxHeight == m_Context.m_Height) - { - SelectContext(false, 0); - Wasm::Test(MaxHeight != m_Context.m_Height); - } + if (MaxHeight != m_Context.m_Height) + return true; + + SelectContext(false, 0); + + if (MaxHeight != m_Context.m_Height) + return true; + + Wasm::Test(IsSuspended()); + return false; } ContractInvokeEntry& ProcessorManager::GenerateKernel(const ContractID* pCid, uint32_t iMethod, const Blob& args, const Shaders::FundsChange* pFunds, uint32_t nFunds, bool bCvtFunds, const char* szComment, uint32_t nCharge) @@ -3131,6 +3205,9 @@ namespace bvm2 { BVM_METHOD(GenerateKernelAdvanced) { + if (!EnsureContext()) + return; + const FundsChange* pFunds_ = get_ArrayAddrAsR(pFunds, nFunds); GenerateKernel(pCid ? &get_AddrAsR(pCid) : nullptr, iMethod, Blob(get_AddrR(pArg, nArg), nArg), pFunds_, nFunds, true, RealizeStr(szComment), nCharge); @@ -3142,6 +3219,9 @@ namespace bvm2 { BVM_METHOD_HOST(GenerateKernelAdvanced) { + if (!EnsureContext()) + return; + GenerateKernel(pCid, iMethod, Blob(pArg, nArg), pFunds, nFunds, false, szComment, nCharge); SetKernelAdv(hMin, hMax, ptFullBlind, ptFullNonce, skForeignSig, iSlotBlind, iSlotNonce, pSig, nSig, pChallenges); } diff --git a/bvm/bvm2.h b/bvm/bvm2.h index b8ef2aa6f..389735445 100644 --- a/bvm/bvm2.h +++ b/bvm/bvm2.h @@ -285,9 +285,15 @@ namespace bvm2 { const HeightPos* FromWasmOpt(Wasm::Word pPos, HeightPos& buf); + bool IsPastFork(uint32_t iFork) + { + assert(iFork < _countof(Rules::get().pForks)); + return get_Height() + 1 >= Rules::get().pForks[iFork].m_Height; + } + bool IsPastHF4() { // current height does not include the current being-interpreted block - return get_Height() + 1 >= Rules::get().pForks[4].m_Height; + return IsPastFork(4); } public: @@ -300,6 +306,7 @@ namespace bvm2 { }; virtual Kind get_Kind() = 0; + virtual bool IsSuspended() { return false; } static void Compile(ByteBuffer&, const Blob&, Kind); @@ -385,9 +392,9 @@ namespace bvm2 { res.n = 0; } - virtual Asset::ID AssetCreate(const Asset::Metadata&, const PeerID&) { return 0; } + virtual Asset::ID AssetCreate(const Asset::Metadata&, const PeerID&, Amount& valDeposit) { return 0; } virtual bool AssetEmit(Asset::ID, const PeerID&, AmountSigned) { return false; } - virtual bool AssetDestroy(Asset::ID, const PeerID&) { return false; } + virtual bool AssetDestroy(Asset::ID, const PeerID&, Amount& valDeposit) { return false; } void HandleAmount(Amount, Asset::ID, bool bLock); void HandleAmountInner(Amount, Asset::ID, bool bLock); @@ -437,7 +444,7 @@ namespace bvm2 { uint32_t m_Charge = Limits::BlockCharge; - virtual void CallFar(const ContractID&, uint32_t iMethod, Wasm::Word pArgs, uint8_t bInheritContext); // can override to invoke host code instead of interpretator (for debugging) + virtual void CallFar(const ContractID&, uint32_t iMethod, Wasm::Word pArgs, uint32_t nArgs, uint8_t bInheritContext); // can override to invoke host code instead of interpretator (for debugging) }; @@ -525,7 +532,7 @@ namespace bvm2 { virtual void SelectContext(bool bDependent, uint32_t nChargeNeeded) = 0; - void EnsureContext(); + bool EnsureContext(); struct Context { Height m_Height = MaxHeight; @@ -598,7 +605,6 @@ namespace bvm2 { std::ostream* m_pOut; bool m_NeedComma = false; - bool m_RawText = false; // don't perform json-style decoration Key::IPKdf::Ptr m_pPKdf; // required for user-related info (account-specific pubkeys, etc.) @@ -614,10 +620,12 @@ namespace bvm2 { bool IsDone() const { return m_Instruction.m_p0 == (const uint8_t*)m_Code.p; } - void InitMem(); + void InitMem(uint32_t nStackBytesExtra = 0); void Call(Wasm::Word addr); void Call(Wasm::Word addr, Wasm::Word retAddr); void CallMethod(uint32_t iMethod); + + void RunOnce(); }; diff --git a/bvm/bvm2_opcodes.h b/bvm/bvm2_opcodes.h index 82e0f0cc4..387036ace 100644 --- a/bvm/bvm2_opcodes.h +++ b/bvm/bvm2_opcodes.h @@ -264,6 +264,9 @@ macro(Height, h) sep \ macro(HashValue&, res) +#define BVMOp_get_ForkHeight(macro, sep) \ + macro(uint32_t, iFork) + #define BVMOp_SelectContext(macro, sep) \ macro(uint8_t, bDependent) sep \ macro(uint32_t, nChargeNeeded) @@ -378,6 +381,11 @@ macro(const char*, szComment) sep \ macro(uint32_t, nCharge) +#define BVMOp_GetApiVersion(macro, sep) \ + +#define BVMOp_SetApiVersion(macro, sep) \ + macro(uint32_t, nVer) + #define BVMOp_GenerateRandom(macro, sep) \ macro(void*, pBuf) sep \ macro(uint32_t, nSize) @@ -474,6 +482,7 @@ macro(0x41, void , get_HdrInfo) \ macro(0x42, void , get_HdrFull) \ macro(0x43, Height , get_RulesCfg) \ + macro(0x44, Height , get_ForkHeight) \ macro(0x48, HashObj* , HashCreateSha256) \ macro(0x49, HashObj* , HashCreateBlake2b) \ macro(0x4A, HashObj* , HashCreateKeccak) \ @@ -542,6 +551,8 @@ macro(0x6B, uint8_t , DocGetNum64) \ macro(0x6C, uint32_t , DocGetBlob) \ macro(0x70, void , GenerateKernel) \ + macro(0x78, uint32_t , GetApiVersion) \ + macro(0x79, void , SetApiVersion) \ macro(0xA0, void , GenerateRandom) \ macro(0xA1, void , get_SlotImage) \ macro(0xA2, void , SlotInit) \ @@ -550,9 +561,9 @@ macro(0xA5, void , GenerateKernelAdvanced) \ macro(0xA6, void , get_SlotImageEx) \ macro(0xA7, void , get_PkEx) \ - macro(0xB0, void , Comm_Listen) \ macro(0xB1, void , Comm_Send) \ macro(0xB2, uint32_t , Comm_Read) \ macro(0xB3, void , Comm_WaitMsg) \ + macro(0xB4, void , Comm_Listen) \ #define EXTRA_LINE_BEFORE_EOF_SO_THAT_THE_STUPID_COMPILER_WONT_COMPLAIN_ABOUT_BACKSLASH_ON_PREVIOUS_LINE diff --git a/bvm/bvm2_shared.h b/bvm/bvm2_shared.h index 9b1e231c4..717405498 100644 --- a/bvm/bvm2_shared.h +++ b/bvm/bvm2_shared.h @@ -165,4 +165,9 @@ struct Stream static const uint32_t s_NonceSlots = 256; +struct ApiVersion +{ + static const uint32_t Current = 1; +}; + #pragma pack (pop) diff --git a/bvm/unittest/contract_test_processor.h b/bvm/unittest/contract_test_processor.h index 317e2baeb..27663b43f 100644 --- a/bvm/unittest/contract_test_processor.h +++ b/bvm/unittest/contract_test_processor.h @@ -191,7 +191,7 @@ namespace beam::bvm2 typedef std::map AssetMap; AssetMap m_Assets; - virtual Asset::ID AssetCreate(const Asset::Metadata& md, const PeerID& pid) override + virtual Asset::ID AssetCreate(const Asset::Metadata& md, const PeerID& pid, Amount& valDeposit) override { Asset::ID aid = AssetCreate2(md, pid); if (aid) @@ -211,6 +211,8 @@ namespace beam::bvm2 auto pUndo = std::make_unique(); pUndo->m_Aid = aid; m_lstUndo.push_back(*pUndo.release()); + + valDeposit = Rules::get().get_DepositForCA(m_Height + 1); } return aid; @@ -270,7 +272,7 @@ namespace beam::bvm2 return true; } - virtual bool AssetDestroy(Asset::ID aid, const PeerID& pid) override + virtual bool AssetDestroy(Asset::ID aid, const PeerID& pid, Amount& valDeposit) override { bool bRet = AssetDestroy2(aid, pid); if (bRet) @@ -292,6 +294,8 @@ namespace beam::bvm2 pUndo->m_Aid = aid; pUndo->m_Pid = pid; m_lstUndo.push_back(*pUndo.release()); + + valDeposit = Rules::get().get_DepositForCA(m_Height + 1); } return bRet; @@ -331,7 +335,7 @@ namespace beam::bvm2 size_t nFrames = m_FarCalls.m_Stack.size(); Wasm::Word nSp = m_Stack.get_AlasSp(); - CallFar(cid, iMethod, nSp, bInheritContext); + CallFar(cid, iMethod, nSp, nArgs, bInheritContext); bool bWasm = false; for (; m_FarCalls.m_Stack.size() > nFrames; m_Cycles++) diff --git a/bvm/unittest/shaders_test.cpp b/bvm/unittest/shaders_test.cpp index 3184f017e..981eb1e72 100644 --- a/bvm/unittest/shaders_test.cpp +++ b/bvm/unittest/shaders_test.cpp @@ -525,7 +525,7 @@ namespace bvm2 { } m_Eth; - virtual void CallFar(const ContractID& cid, uint32_t iMethod, Wasm::Word pArgs, uint8_t bInheritContext) override + virtual void CallFar(const ContractID& cid, uint32_t iMethod, Wasm::Word pArgs, uint32_t nArgs, uint8_t bInheritContext) override { if (cid == m_Vault.m_Cid) { @@ -732,7 +732,7 @@ namespace bvm2 { } } */ - ProcessorContract::CallFar(cid, iMethod, pArgs, bInheritContext); + ProcessorContract::CallFar(cid, iMethod, pArgs, nArgs, bInheritContext); } void TestVault(); @@ -2147,7 +2147,7 @@ namespace bvm2 { r.pForks[3].m_Height = 999999999; r.pForks[3].m_Hash = Zero; - r.pForks[4].m_Height = MaxHeight; + r.DisableForksFrom(4); beam::Block::SystemState::Full s; diff --git a/core/block_crypt.cpp b/core/block_crypt.cpp index 909ae4ee8..d951fff23 100644 --- a/core/block_crypt.cpp +++ b/core/block_crypt.cpp @@ -1002,7 +1002,7 @@ namespace beam hp.Serialize(m_Signature); } - bool TxKernelAssetControl::IsValid(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent /* = nullptr */) const + bool TxKernelAssetControl::IsValidAssetCtl(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent) const { if (!IsValidBase(hScheme, exc, pParent)) return false; @@ -1081,7 +1081,7 @@ namespace beam bool TxKernelAssetEmit::IsValid(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent /* = nullptr */) const { - if (!TxKernelAssetControl::IsValid(hScheme, exc, pParent)) + if (!TxKernelAssetControl::IsValidAssetCtl(hScheme, exc, pParent)) return false; if (!m_Value || !m_AssetID) @@ -1120,13 +1120,13 @@ namespace beam // TxKernelAssetCreate bool TxKernelAssetCreate::IsValid(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent /* = nullptr */) const { - if (!TxKernelAssetControl::IsValid(hScheme, exc, pParent)) + if (!TxKernelAssetControl::IsValidAssetCtl(hScheme, exc, pParent)) return false; if (m_MetaData.m_Value.size() > Asset::Info::s_MetadataMaxSize) return false; - ECC::Point::Native pt = ECC::Context::get().H * Rules::get().CA.DepositForList; + ECC::Point::Native pt = ECC::Context::get().H * Rules::get().get_DepositForCA(hScheme); exc += pt; return true; @@ -1158,14 +1158,27 @@ namespace beam { TxKernelAssetControl::HashSelfForMsg(hp); hp << m_AssetID; + + if (IsCustomDeposit()) + hp << m_Deposit; + } + + bool TxKernelAssetDestroy::IsCustomDeposit() const + { + return (m_Height.m_Min >= Rules::get().pForks[5].m_Height); + } + + Amount TxKernelAssetDestroy::get_Deposit() const + { + return IsCustomDeposit() ? m_Deposit : Rules::get().CA.DepositForList2; } bool TxKernelAssetDestroy::IsValid(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent /* = nullptr */) const { - if (!TxKernelAssetControl::IsValid(hScheme, exc, pParent)) + if (!TxKernelAssetControl::IsValidAssetCtl(hScheme, exc, pParent)) return false; - ECC::Point::Native pt = ECC::Context::get().H * Rules::get().CA.DepositForList; + ECC::Point::Native pt = ECC::Context::get().H * get_Deposit(); pt = -pt; exc += pt; @@ -1180,6 +1193,7 @@ namespace beam v.CopyFrom(*this); v.m_AssetID = m_AssetID; + v.m_Deposit = m_Deposit; } ///////////// @@ -1887,10 +1901,9 @@ namespace beam pForks[2].m_Height = 777777; pForks[3].m_Height = 1280000; pForks[4].m_Height = 1820000; + pForks[5].m_Height = 1920000; - // future forks - for (size_t i = 5; i < _countof(pForks); i++) - pForks[i].m_Height = MaxHeight; + DisableForksFrom(6); // future forks } Amount Rules::get_EmissionEx(Height h, Height& hEnd, Amount base) const @@ -2057,7 +2070,7 @@ namespace beam << Shielded.m_ProofMin.M << Shielded.MaxWindowBacklog << CA.Enabled - << CA.DepositForList + << CA.DepositForList2 << CA.LockPeriod << CA.m_ProofCfg.n << CA.m_ProofCfg.M @@ -2077,6 +2090,12 @@ namespace beam << pForks[4].m_Height // no more flexible parameters so far >> pForks[4].m_Hash; + + oracle + << "fork5" + << pForks[5].m_Height + << CA.DepositForList5 + >> pForks[5].m_Hash; } const HeightHash* Rules::FindFork(const Merkle::Hash& hv) const @@ -2128,6 +2147,17 @@ namespace beam return pForks[i]; } + void Rules::DisableForksFrom(uint32_t i) + { + for (; i < _countof(pForks); i++) + pForks[i].m_Height = MaxHeight; + } + + Amount Rules::get_DepositForCA(Height hScheme) const + { + return (hScheme >= pForks[5].m_Height) ? CA.DepositForList5 : CA.DepositForList2; + } + std::string Rules::get_SignatureStr() const { std::ostringstream os; @@ -2654,20 +2684,6 @@ namespace beam m_Offset = offs; } - bool Block::BodyBase::IsValid(const HeightRange& hr, TxBase::IReader&& r) const - { - if ((hr.m_Min < Rules::HeightGenesis) || hr.IsEmpty()) - return false; - - TxBase::Context::Params pars; - TxBase::Context ctx(pars); - ctx.m_Height = hr; - - return - ctx.ValidateAndSummarize(*this, std::move(r)) && - ctx.IsValidBlock(); - } - ///////////// // SystemState::IHistory bool Block::SystemState::IHistory::get_Tip(Full& s) @@ -2900,16 +2916,30 @@ namespace beam return m_Owner != Zero && m_LockHeight != Zero; } + bool Asset::Info::IsDefDeposit() const + { + return (Rules::get().CA.DepositForList2 == m_Deposit); + } + void Asset::Full::get_Hash(ECC::Hash::Value& hv) const { - ECC::Hash::Processor() + ECC::Hash::Processor hp; + hp << "B.Asset.V1" << m_ID << m_Value << m_Owner << m_LockHeight - << m_Metadata.m_Hash - >> hv; + << m_Metadata.m_Hash; + + if (!IsDefDeposit()) + { + hp + << "deposit" + << m_Deposit; + } + + hp >> hv; } void Asset::Metadata::Reset() diff --git a/core/block_crypt.h b/core/block_crypt.h index e75eadf2d..089bd6f10 100644 --- a/core/block_crypt.h +++ b/core/block_crypt.h @@ -167,6 +167,7 @@ namespace beam AmountBig::Type m_Value = Zero; PeerID m_Owner = 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 @@ -174,6 +175,7 @@ namespace beam bool IsEmpty() const; bool IsValid() const; bool Recognize(Key::IPKdf&) const; + bool IsDefDeposit() const; }; struct Full @@ -280,7 +282,8 @@ namespace beam struct { bool Enabled = true; - Amount DepositForList = Coin * 3000; + Amount DepositForList2 = Coin * 3000; // after HF2 + Amount DepositForList5 = Coin * 10; // after HF5 Height LockPeriod = 1440; // how long it's locked (can't be destroyed) after it was completely burned Sigma::Cfg m_ProofCfg = { 4, 3 }; // 4^3 = 64 } CA; @@ -328,13 +331,15 @@ namespace beam static void get_Emission(AmountBig::Type&, const HeightRange&); static void get_Emission(AmountBig::Type&, const HeightRange&, Amount base); - HeightHash pForks[5]; + HeightHash pForks[6]; const HeightHash& get_LastFork() const; const HeightHash* FindFork(const Merkle::Hash&) const; uint32_t FindFork(Height) const; Height get_ForkMaxHeightSafe(uint32_t iFork) const; + void DisableForksFrom(uint32_t); std::string get_SignatureStr() const; + Amount get_DepositForCA(Height hScheme) const; private: Amount get_EmissionEx(Height, Height& hEnd, Amount base) const; @@ -978,9 +983,9 @@ namespace beam void get_Sk(ECC::Scalar::Native&, Key::IKdf&); // pseudo-random sk for this kernel - virtual bool IsValid(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent = nullptr) const override; protected: void CopyFrom(const TxKernelAssetControl&); + bool IsValidAssetCtl(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent) const; virtual void HashSelfForMsg(ECC::Hash::Processor&) const override; virtual void HashSelfForID(ECC::Hash::Processor&) const override; }; @@ -1025,8 +1030,12 @@ namespace beam typedef std::unique_ptr Ptr; Asset::ID m_AssetID; + Amount m_Deposit = 0; TxKernelAssetDestroy(): m_AssetID(Asset::s_InvalidID) {} + bool IsCustomDeposit() const; + Amount get_Deposit() const; + virtual ~TxKernelAssetDestroy() {} virtual Subtype::Enum get_Subtype() const override; virtual bool IsValid(Height hScheme, ECC::Point::Native& exc, const TxKernel* pParent = nullptr) const override; @@ -1452,15 +1461,6 @@ namespace beam { void ZeroInit(); - // Test the following: - // Validity of all the components, and overall arithmetics, whereas explicit fees are already collected by extra UTXO(s) put by the miner - // All components are specified in a lexicographical order, to conceal the actual transaction graph - // Liquidity of the components wrt height and maturity policies - // Not tested by this function (but should be tested by nodes!) - // Existence of all the input UTXOs - // Existence of the coinbase non-confidential output UTXO, with the sum amount equal to the new coin emission. - bool IsValid(const HeightRange&, TxBase::IReader&&) const; - struct IMacroReader :public IReader { @@ -1484,10 +1484,6 @@ namespace beam :public BodyBase ,public TxVectors::Full { - bool IsValid(const HeightRange& hr) const - { - return BodyBase::IsValid(hr, get_Reader()); - } }; struct ChainWorkProof; diff --git a/core/serialization_adapters.h b/core/serialization_adapters.h index f046168cf..375c42ad4 100644 --- a/core/serialization_adapters.h +++ b/core/serialization_adapters.h @@ -1548,6 +1548,8 @@ namespace detail { saveBase(ar, val); ar & val.m_AssetID; + if (val.IsCustomDeposit()) + ar & val.m_Deposit; return ar; } @@ -1556,6 +1558,8 @@ namespace detail { load0Base(ar, val, nRecursion); ar & val.m_AssetID; + if (val.IsCustomDeposit()) + ar & val.m_Deposit; } /// beam::TxKernelShieldedOutput serialization @@ -1966,11 +1970,23 @@ 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; ar & v.m_Owner & v.m_Value - & v.m_LockHeight + & h & v.m_Metadata; + + if (!bDef) + { + uint32_t nFlags = 1; // reserve other flags for future use + ar + & nFlags + & v.m_LockHeight + & v.m_Deposit; + } + return ar; } @@ -1982,6 +1998,20 @@ namespace detail & v.m_Value & v.m_LockHeight & v.m_Metadata; + + v.m_Deposit = beam::Rules::get().CA.DepositForList2; + + if (beam::MaxHeight == v.m_LockHeight) + { + uint32_t nFlags; + ar + & nFlags + & v.m_LockHeight; + + if (1 & nFlags) + ar & v.m_Deposit; + } + return ar; } diff --git a/core/uintBig.cpp b/core/uintBig.cpp index bbed1656c..8a665c597 100644 --- a/core/uintBig.cpp +++ b/core/uintBig.cpp @@ -88,6 +88,66 @@ namespace beam { sz[nDst << 1] = 0; } + uint32_t uintBigImpl::_PrintDecimal(uint8_t* pDst, uint32_t nDst, char* sz, uint8_t* pTmp1, uint8_t* pTmp2, uint8_t* pTmp3) + { + uint32_t nRes = 0; + + const uint32_t nDigs = 9; + typedef uint32_t TSection; + const TSection nSegment = 1000000000u; + uintBigFor::Type div(nSegment); + + while (true) + { + _Div(pTmp1, nDst, pDst, nDst, div.m_pData, div.nBytes, pTmp2, pTmp3); + // pTmp1 == pDst / div + // pTmp2 == pTmp1 * div + + bool bLast = memis0(pTmp1, nDst); + if (!bLast) + { + _Inv(pTmp2, nDst); + _Inc(pTmp2, nDst); + _Inc(pDst, nDst, pTmp2, nDst); + // pDst == resid + } + + uintBigFor::Type valResid; + _Assign(valResid.m_pData, valResid.nBytes, pDst, nDst); + + TSection nResid; + valResid.Export(nResid); + + uint32_t nPrintDigs = nDigs; + if (bLast) + { + // could be less + nPrintDigs = 1; + for (auto val = nResid; val /= 10; ) + nPrintDigs++; + } + + memmove(sz + nPrintDigs, sz, nRes); + nRes += nPrintDigs; + + for (uint32_t i = 0; ; nResid /= 10) + { + ++i; + sz[nPrintDigs - i] = '0' + (nResid % 10); + if (i == nPrintDigs) + break; + } + + if (bLast) + break; + + memcpy(pDst, pTmp1, nDst); + } + + sz[nRes] = 0; + return nRes; + } + uint32_t uintBigImpl::_Scan(uint8_t* pDst, const char* sz, uint32_t nTxtLen) { uint32_t ret = 0; diff --git a/core/uintBig.h b/core/uintBig.h index dd01e2a16..d0cbd1ddd 100644 --- a/core/uintBig.h +++ b/core/uintBig.h @@ -40,6 +40,7 @@ namespace beam static void _Print(const uint8_t* pDst, uint32_t nDst, std::ostream&); // truncates if too long static void _PrintFull(const uint8_t* pDst, uint32_t nDst, std::ostream&); static void _Print(const uint8_t* pDst, uint32_t nDst, char*); + static uint32_t _PrintDecimal(uint8_t* pDst, uint32_t nDst, char*, uint8_t* pTmp1, uint8_t* pTmp2, uint8_t* pTmp3); static std::string _Str(const uint8_t* pDst, uint32_t nDst); static uint32_t _Scan(uint8_t* pDst, const char*, uint32_t nTxtLen); @@ -336,11 +337,20 @@ namespace beam static const uint32_t nTxtLen = nBytes * 2; // not including 0-term + static const uint32_t nTxtLen10Max = 10 * ((nBytes + 3) / 4); // upper bound, practically could be less + void Print(char* sz) const { _Print(m_pData, nBytes, sz); } + uint32_t PrintDecimal(char* sz) const + { + uintBig_t dup(*this); + uintBig_t tmp1, tmp2, tmp3; + return _PrintDecimal(dup.m_pData, nBytes, sz, tmp1.m_pData, tmp2.m_pData, tmp3.m_pData); + } + uint32_t Scan(const char* sz) { // returns the number of text characters processed. If less than nTxtLen - the remaining bytes are not modified diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index 214738022..06bc0a74e 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -418,75 +418,172 @@ class Adapter : public Node::IObserver, public IAdapter { struct Writer { - std::ostringstream m_os; - bool m_Empty = true; + json m_json; - void Next() + template + static void AddHex(json& j, const char* szName, const uintBig_t& val) { - if (m_Empty) - m_Empty = false; - else - m_os << ", "; + char sz[uintBig_t::nTxtLen + 1]; + val.Print(sz); + j[szName] = sz; + } + + static void AddPt(json& j, const char* szName, const ECC::Point& pt) + { + typedef uintBig_t MyPoint; + AddHex(j, szName, Cast::Reinterpret(pt)); + } + + void AddCommitment(const ECC::Point& pt) + { + AddPt(m_json, "commitment", pt); + } + + Writer() + { + m_json = json::object(); } void OnAsset(const Asset::Proof* pProof) { if (pProof) { - Next(); auto t0 = pProof->m_Begin; - m_os << "Asset [" << t0 << "-" << t0 + Rules::get().CA.m_ProofCfg.get_N() - 1 << "]"; + + m_json.push_back( + { "Asset", + { + {"min", t0}, + {"max", t0 + Rules::get().CA.m_ProofCfg.get_N() - 1}, + }, + } + ); } } void OnContract(const NodeProcessor::ContractInvokeExtraInfo& info) { - m_os << "Contract " << info.m_Cid << ", " << info.m_sParsed; + json j2 = json::object(); + m_json.swap(j2); + + OnContractInternal(info); + + m_json.swap(j2); + m_json["contract"] = std::move(j2); + } - for (auto it = info.m_FundsIO.m_Map.begin(); info.m_FundsIO.m_Map.end() != it; it++) + void OnContractInternal(const NodeProcessor::ContractInvokeExtraInfo& info) + { + if (!info.m_sParsed.empty()) { - m_os << ", "; + std::string sFormed; + sFormed.reserve(info.m_sParsed.size() + 2); + sFormed += '{'; + sFormed += info.m_sParsed; + sFormed += '}'; + + m_json = json::parse(sFormed); + } + + AddHex(m_json, "cid", info.m_Cid); + + if (info.m_sParsed.empty()) + { + if (info.m_Sid.has_value()) + AddHex(m_json, "sid", *info.m_Sid); + + m_json["iMethod"] = info.m_iMethod; - auto valBig = it->second; - if (valBig.get_Msb()) + if (!info.m_Args.empty()) { - valBig.Negate(); - m_os << "Spend"; - } else - m_os << "Receive"; + std::string sBuf; + sBuf.resize(info.m_Args.size() * 2); + uintBigImpl::_Print(&info.m_Args.front(), (uint32_t)info.m_Args.size(), &sBuf.front()); + m_json["args"] = std::move(sBuf); + } + } + + if (!info.m_FundsIO.m_Map.empty()) + { + json jF = json::array(); - auto aid = it->first; - if (aid) - m_os << " Asset-" << aid; + for (auto it = info.m_FundsIO.m_Map.begin(); info.m_FundsIO.m_Map.end() != it; it++) + { + json jItem = json::object(); + + const char* szAction; + auto valBig = it->second; + if (valBig.get_Msb()) + { + valBig.Negate(); + szAction = "Spend"; + } + else + szAction = "Receive"; - // currently ignore val-big part - m_os << " " << AmountBig::get_Lo(valBig); + jItem["action"] = szAction; + jItem["val"] = AmountBig::get_Lo(valBig); + + auto valHi = AmountBig::get_Hi(valBig); + if (valHi) + jItem["valHi"] = valHi; + + auto aid = it->first; + if (aid) + jItem["aid"] = aid; + + + jF.push_back(std::move(jItem)); + } + + m_json["funds"] = std::move(jF); } - for (uint32_t iSig = 0; iSig < info.m_vSigs.size(); iSig++) + if (!info.m_vSigs.empty()) { - typedef uintBig_t MyPoint; - const auto& val = Cast::Reinterpret(info.m_vSigs[iSig]); + json jS = json::array(); + + for (uint32_t iSig = 0; iSig < info.m_vSigs.size(); iSig++) + { + json jItem = json::object(); + + AddPt(jItem, "pk", info.m_vSigs[iSig]); + + jS.push_back(std::move(jItem)); - char sz[MyPoint::nTxtLen + 1]; - val.Print(sz); + } - m_os << ", Sign " << sz; + m_json["sigs"] = std::move(jS); } - for (size_t i = 0; i < info.m_vNested.size(); i++) + + if (info.m_NumNested) { - m_os << ", [ "; - OnContract(info.m_vNested[i]); - m_os << " ]"; + json j2 = json::array(); + + for (uint32_t iNested = 0; iNested < info.m_NumNested; ) + { + const auto& infoNested = (&info)[++iNested]; + iNested += infoNested.m_NumNested; + + json j3 = json::object(); + m_json.swap(j3); + + OnContractInternal(infoNested); + + m_json.swap(j3); + j2.push_back(std::move(j3)); + } + + m_json["nested"] = std::move(j2); } } }; - static std::string get(const Asset::Metadata& md) + static std::string FmtMD(const Asset::Metadata& md) { std::string sMetadata; - const ByteBuffer& bb = md.m_Value; // alias +/* const ByteBuffer& bb = md.m_Value; // alias sMetadata.reserve(bb.size()); for (size_t i = 0; i < bb.size(); i++) { @@ -495,108 +592,110 @@ class Adapter : public Node::IObserver, public IAdapter { ch = '?'; sMetadata.push_back(ch); } - +*/ + md.get_String(sMetadata); return sMetadata; } - static std::string get(const Output& outp, Height h, Height hMaturity) + static json get(const Output& outp, Height h, Height hMaturity) { Writer w; + w.AddCommitment(outp.m_Commitment); if (outp.m_Coinbase) - { - w.Next(); - w.m_os << "Coinbase"; - } + w.m_json["type"] = "Coinbase"; if (outp.m_pPublic) - { - w.Next(); - w.m_os << "Value=" << outp.m_pPublic->m_Value; - } + w.m_json["Value"] = outp.m_pPublic->m_Value; if (outp.m_Incubation) - { - w.Next(); - w.m_os << "Incubation +" << outp.m_Incubation; - } + w.m_json["Incubation"] = outp.m_Incubation; if (hMaturity != h) - { - w.Next(); - w.m_os << "Maturity=" << hMaturity; - } + w.m_json["Maturity"] = hMaturity; w.OnAsset(outp.m_pAsset.get()); - return w.m_os.str(); + return std::move(w.m_json); } - static std::string get(const TxKernel& krn, Amount& fee, ContractRichInfo& cri) + static json get(const TxKernel& krn, Amount& fee, ContractRichInfo& cri) { struct MyWalker - :public TxKernel::IWalker { Writer m_Wr; - Amount m_Fee = 0; ContractRichInfo* m_pCri; - virtual bool OnKrn(const TxKernel& krn) override + void OnKrn(const TxKernel& krn) { - m_Fee += krn.m_Fee; - switch (krn.get_Subtype()) { #define THE_MACRO(id, name) case id: OnKrnEx(Cast::Up(krn)); break; BeamKernelsAll(THE_MACRO) #undef THE_MACRO } - - return true; } void OnKrnEx(const TxKernelStd& krn) { if (krn.m_pRelativeLock) { - m_Wr.Next(); - m_Wr.m_os << "Rel.Lock ID=" << krn.m_pRelativeLock->m_ID << " H=" << krn.m_pRelativeLock->m_LockHeight; + json j = json::object(); + Writer::AddHex(j, "ID", krn.m_pRelativeLock->m_ID); + j["height"] = krn.m_pRelativeLock->m_LockHeight; + m_Wr.m_json["Rel.Lock"] = std::move(j); } if (krn.m_pHashLock) { - m_Wr.Next(); - m_Wr.m_os << "Hash.Lock Preimage=" << krn.m_pHashLock->m_Value; + json j = json::object(); + Writer::AddHex(j, "Preimage", krn.m_pHashLock->m_Value); + m_Wr.m_json["Hash.Lock"] = std::move(j); } } void OnKrnEx(const TxKernelAssetCreate& krn) { - m_Wr.Next(); - m_Wr.m_os << "Asset.Create MD.Hash=" << krn.m_MetaData.m_Hash; + json j = json::object(); + j["MD"] = FmtMD(krn.m_MetaData); + Writer::AddHex(j, "MD.Hash", krn.m_MetaData.m_Hash); + m_Wr.m_json["Asset.Create"] = std::move(j); } void OnKrnEx(const TxKernelAssetDestroy& krn) { - m_Wr.Next(); - m_Wr.m_os << "Asset.Destroy ID=" << krn.m_AssetID; + json j = json::object(); + j["ID"] = krn.m_AssetID; + m_Wr.m_json["Asset.Destroy"] = std::move(j); } void OnKrnEx(const TxKernelAssetEmit& krn) { - m_Wr.Next(); - m_Wr.m_os << "Asset.Emit ID=" << krn.m_AssetID << " Value=" << krn.m_Value; + json j = json::object(); + j["ID"] = krn.m_AssetID; + j["Value"] = krn.m_Value; + m_Wr.m_json["Asset.Emit"] = std::move(j); } void OnKrnEx(const TxKernelShieldedOutput& krn) { - m_Wr.Next(); - m_Wr.m_os << "Shielded.Out"; + json j = json::object(); + + m_Wr.m_json.swap(j); m_Wr.OnAsset(krn.m_Txo.m_pAsset.get()); + m_Wr.m_json.swap(j); + + m_Wr.m_json["Shielded.Out"] = std::move(j); } void OnKrnEx(const TxKernelShieldedInput& krn) { + json j = json::object(); + + m_Wr.m_json.swap(j); + m_Wr.OnAsset(krn.m_pAsset.get()); + m_Wr.m_json.swap(j); + uint32_t n = krn.m_SpendProof.m_Cfg.get_N(); TxoID id0 = krn.m_WindowEnd; @@ -605,21 +704,22 @@ class Adapter : public Node::IObserver, public IAdapter { else id0 = 0; - m_Wr.Next(); - m_Wr.m_os << "Shielded.In Set=[" << id0 << "-" << krn.m_WindowEnd - 1 << "]"; - m_Wr.OnAsset(krn.m_pAsset.get()); + j["min"] = id0; + j["max"] = krn.m_WindowEnd - 1; + + m_Wr.m_json["Shielded.In"] = std::move(j); } void OnKrnEx(const TxKernelContractCreate& krn) { - m_Wr.Next(); - auto pInfo = m_pCri->get_Next(); if (pInfo) m_Wr.OnContract(*pInfo); else { NodeProcessor::ContractInvokeExtraInfo info; + info.m_NumNested = 0; + info.m_iParent = 0; bvm2::ShaderID sid; bvm2::get_ShaderID(sid, krn.m_Data); @@ -633,8 +733,6 @@ class Adapter : public Node::IObserver, public IAdapter { void OnKrnEx(const TxKernelContractInvoke& krn) { - m_Wr.Next(); - auto pInfo = m_pCri->get_Next(); if (pInfo) m_Wr.OnContract(*pInfo); @@ -650,16 +748,28 @@ class Adapter : public Node::IObserver, public IAdapter { } wlk; wlk.m_pCri = &cri; + Writer::AddHex(wlk.m_Wr.m_json, "id", krn.m_Internal.m_ID); + wlk.m_Wr.m_json["minHeight"] = krn.m_Height.m_Min; + wlk.m_Wr.m_json["maxHeight"] = krn.m_Height.m_Max; + + fee += krn.m_Fee; + + wlk.OnKrn(krn); + if (!krn.m_vNested.empty()) { - wlk.m_Wr.Next(); - wlk.m_Wr.m_os << "Composite"; - } + json j2 = json::array(); - wlk.Process(krn); - fee = wlk.m_Fee; + for (uint32_t i = 0; i < krn.m_vNested.size(); i++) + { + json j3 = get(*krn.m_vNested[i], fee, cri); + j2.push_back(std::move(j3)); + } - return wlk.m_Wr.m_os.str(); + wlk.m_Wr.m_json["nested"] = std::move(j2); + } + + return std::move(wlk.m_Wr.m_json); } }; @@ -892,40 +1002,24 @@ class Adapter : public Node::IObserver, public IAdapter { Height hCreate = inp.m_Internal.m_Maturity - outp.get_MinMaturity(0); - inputs.push_back( - json{ - {"commitment", uint256_to_hex(buf, outp.m_Commitment.m_X)}, - {"height", hCreate}, - {"extra", ExtraInfo::get(outp, hCreate, inp.m_Internal.m_Maturity)} - } - ); + json jItem = ExtraInfo::get(outp, hCreate, inp.m_Internal.m_Maturity); + jItem["height"] = hCreate; + + inputs.push_back(std::move(jItem)); } json outputs = json::array(); - for (const auto &v : block.m_vOutputs) { - outputs.push_back( - json{ - {"commitment", uint256_to_hex(buf, v->m_Commitment.m_X)}, - {"extra", ExtraInfo::get(*v, height, v->get_MinMaturity(height))} - } - ); - } + for (const auto &v : block.m_vOutputs) + outputs.push_back(ExtraInfo::get(*v, height, v->get_MinMaturity(height))); json kernels = json::array(); for (const auto &v : block.m_vKernels) { Amount fee = 0; - std::string sExtra = ExtraInfo::get(*v, fee, cri); + json j = ExtraInfo::get(*v, fee, cri); + j["fee"] = fee; - kernels.push_back( - json{ - {"id", hash_to_hex(buf, v->m_Internal.m_ID)}, - {"minHeight", v->m_Height.m_Min}, - {"maxHeight", v->m_Height.m_Max}, - {"fee", fee}, - {"extra", sExtra} - } - ); + kernels.push_back(std::move(j)); } json assets = json::array(); @@ -941,7 +1035,7 @@ class Adapter : public Node::IObserver, public IAdapter { assets.push_back( json{ {"id", ai.m_ID}, - {"metadata", ExtraInfo::get(ai.m_Metadata)}, + {"metadata", ExtraInfo::FmtMD(ai.m_Metadata)}, {"metahash", hash_to_hex(buf, ai.m_Metadata.m_Hash)}, {"owner", hash_to_hex(buf, ai.m_Owner)}, {"value_lo", AmountBig::get_Lo(ai.m_Value)}, diff --git a/node/db.cpp b/node/db.cpp index 9290e89d3..d486dc706 100644 --- a/node/db.cpp +++ b/node/db.cpp @@ -100,6 +100,7 @@ namespace beam { #define TblAssets_Owner "Owner" #define TblAssets_Value "Value" #define TblAssets_Data "MetaData" +#define TblAssets_Deposit "Deposit" #define TblAssets_LockHeight "LockHeight" #define TblAssetEvts "AssetsEvents" @@ -127,8 +128,9 @@ namespace beam { #define TblCache_LastHit "Hit" #define TblKrnInfo "KrnInfo" -#define TblKrnInfo_Key "Key" -#define TblKrnInfo_Data "Data" +#define TblKrnInfo_Pos "Pos" +#define TblKrnInfo_Key "Key" +#define TblKrnInfo_Data "Data" NodeDB::NodeDB() :m_pDb(nullptr) @@ -365,7 +367,7 @@ void NodeDB::Open(const char* szPath) bCreate = !rs.Step(); } - const uint64_t nVersionTop = 30; + const uint64_t nVersionTop = 32; Transaction t(*this); @@ -431,12 +433,22 @@ void NodeDB::Open(const char* szPath) // no break; case 29: // Block interpretation nKrnIdx fixed to match KrnWalker's - ParamIntSet(ParamID::Flags1, ParamIntGetDef(ParamID::Flags1) | Flags1::PendingRebuildNonStd); - CreateTables29(); + ExecQuick("DROP TABLE IF EXISTS " TblKrnInfo); + // no break; + + case 30: // Block interpretation nKrnIdx fixed to match KrnWalker's + ExecQuick("DROP TABLE IF EXISTS " TblKrnInfo); + CreateTables30(); // no break; + case 31: + ExecQuick("DROP TABLE IF EXISTS " TblAssets); + CreateTables31(); + + ParamIntSet(ParamID::Flags1, ParamIntGetDef(ParamID::Flags1) | Flags1::PendingRebuildNonStd); ParamIntSet(ParamID::DbVer, nVersionTop); + // no break; case nVersionTop: break; @@ -560,7 +572,8 @@ void NodeDB::Create() CreateTables23(); CreateTables27(); CreateTables28(); - CreateTables29(); + CreateTables30(); + CreateTables31(); } void NodeDB::CreateTables20() @@ -572,15 +585,6 @@ void NodeDB::CreateTables20() ExecQuick("CREATE TABLE [" TblUnique "] (" "[" TblUnique_Key "] BLOB NOT NULL PRIMARY KEY," "[" TblUnique_Value "] BLOB) WITHOUT ROWID"); - - ExecQuick("CREATE TABLE [" TblAssets "] (" - "[" TblAssets_ID "] INTEGER NOT NULL PRIMARY KEY," - "[" TblAssets_Owner "] BLOB," - "[" TblAssets_Data "] BLOB," - "[" TblAssets_LockHeight "] INTEGER," - "[" TblAssets_Value "] BLOB)"); - - ExecQuick("CREATE INDEX [Idx" TblAssets "Own] ON [" TblAssets "] ([" TblAssets_Owner "])"); } void NodeDB::CreateTables21() @@ -631,11 +635,28 @@ void NodeDB::CreateTables28() ExecQuick("CREATE INDEX [Idx" TblCache "_Hit" "] ON [" TblCache "] ([" TblCache_LastHit "]);"); } -void NodeDB::CreateTables29() +void NodeDB::CreateTables30() { - ExecQuick("CREATE TABLE [" TblKrnInfo "] (" - "[" TblKrnInfo_Key "] INTEGER NOT NULL PRIMARY KEY," - "[" TblKrnInfo_Data "] BLOB NOT NULL)"); + ExecQuick("CREATE TABLE [" TblKrnInfo "] (" + "[" TblKrnInfo_Pos "] BLOB NOT NULL PRIMARY KEY," + "[" TblKrnInfo_Key "] BLOB NOT NULL," + "[" TblKrnInfo_Data "] BLOB NOT NULL" + ") WITHOUT ROWID"); + + ExecQuick("CREATE INDEX [Idx" TblKrnInfo "_Key" "] ON [" TblKrnInfo "] ([" TblKrnInfo_Key "],[" TblKrnInfo_Pos "]);"); +} + +void NodeDB::CreateTables31() +{ + ExecQuick("CREATE TABLE [" TblAssets "] (" + "[" TblAssets_ID "] INTEGER NOT NULL PRIMARY KEY," + "[" TblAssets_Owner "] BLOB," + "[" TblAssets_Data "] BLOB," + "[" TblAssets_Deposit "] INTEGER," + "[" TblAssets_LockHeight "] INTEGER," + "[" TblAssets_Value "] BLOB)"); + + ExecQuick("CREATE INDEX [Idx" TblAssets "Own] ON [" TblAssets "] ([" TblAssets_Owner "])"); } void NodeDB::Vacuum() @@ -2706,15 +2727,16 @@ 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_Value "," TblAssets_LockHeight ") VALUES(?,?,?,?,?)"); + Recordset rs(*this, Query::AssetAdd, "INSERT INTO " TblAssets "(" TblAssets_ID "," TblAssets_Owner "," 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_As(3, pAi->m_Value); - rs.put(4, pAi->m_LockHeight); + rs.put(3, pAi->m_Deposit); + rs.put_As(4, pAi->m_Value); + rs.put(5, pAi->m_LockHeight); } rs.Step(); @@ -2801,7 +2823,7 @@ void NodeDB::AssetsDelAll() bool NodeDB::AssetGetSafe(Asset::Full& ai) { - Recordset rs(*this, Query::AssetGet, "SELECT " TblAssets_Value "," TblAssets_Owner "," TblAssets_Data "," TblAssets_LockHeight " FROM " TblAssets " WHERE " TblAssets_ID "=?"); + Recordset rs(*this, Query::AssetGet, "SELECT " TblAssets_Value "," TblAssets_Owner "," TblAssets_Data "," TblAssets_Deposit "," TblAssets_LockHeight " FROM " TblAssets " WHERE " TblAssets_ID "=?"); rs.put(0, ai.m_ID); if (!rs.Step()) return false; @@ -2809,7 +2831,8 @@ bool NodeDB::AssetGetSafe(Asset::Full& ai) 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_LockHeight); + rs.get(3, ai.m_Deposit); + rs.get(4, ai.m_LockHeight); ai.m_Metadata.UpdateHash(); @@ -3059,20 +3082,26 @@ bool NodeDB::WalkerContractData::MoveNext() return true; } -void put_ContractLogPos(NodeDB::Recordset& rs, int iCol, const HeightPos& pos, NodeDB::ContractLog::PosPacked& buf) +void NodeDB::HeightPosPacked::put(NodeDB::Recordset& rs, int iCol, const HeightPos& pos) { - buf.m_Height = pos.m_Height; - buf.m_Idx = pos.m_Pos; + m_Height = pos.m_Height; + m_Idx = pos.m_Pos; + rs.put(iCol, Blob(this, sizeof(*this))); +} - rs.put(iCol, Blob(&buf, sizeof(buf))); +void NodeDB::HeightPosPacked::get(NodeDB::Recordset& rs, int iCol, HeightPos& pos) +{ + const auto& x = rs.get_As(iCol); + x.m_Height.Export(pos.m_Height); + x.m_Idx.Export(pos.m_Pos); } void NodeDB::ContractLogInsert(const ContractLog::Entry& x) { Recordset rs(*this, Query::ContractLogInsert, "INSERT INTO " TblContractLogs " (" TblContractLogs_Pos "," TblContractLogs_Key "," TblContractLogs_Data ") VALUES(?,?,?)"); - ContractLog::PosPacked buf; - put_ContractLogPos(rs, 0, x.m_Pos, buf); + HeightPosPacked buf; + buf.put(rs, 0, x.m_Pos); rs.put(1, x.m_Key); rs.put(2, x.m_Val); @@ -3085,9 +3114,9 @@ void NodeDB::ContractLogDel(const HeightPos& posMin, const HeightPos& posMax) { Recordset rs(*this, Query::ContractLogDel, "DELETE FROM " TblContractLogs " WHERE " TblContractLogs_Pos " BETWEEN ? AND ?"); - NodeDB::ContractLog::PosPacked bufMin, bufMax; - put_ContractLogPos(rs, 0, posMin, bufMin); - put_ContractLogPos(rs, 1, posMax, bufMax); + HeightPosPacked bufMin, bufMax; + bufMin.put(rs, 0, posMin); + bufMax.put(rs, 1, posMax); rs.Step(); } @@ -3096,8 +3125,8 @@ void NodeDB::ContractLogEnum(ContractLog::Walker& wlk, const HeightPos& posMin, { wlk.m_Rs.Reset(*this, Query::ContractLogEnum, "SELECT * FROM " TblContractLogs " WHERE " TblContractLogs_Pos " BETWEEN ? AND ? ORDER BY " TblContractLogs_Pos); - put_ContractLogPos(wlk.m_Rs, 0, posMin, wlk.m_bufMin); - put_ContractLogPos(wlk.m_Rs, 1, posMax, wlk.m_bufMax); + wlk.m_bufMin.put(wlk.m_Rs, 0, posMin); + wlk.m_bufMax.put(wlk.m_Rs, 1, posMax); } void NodeDB::ContractLogEnum(ContractLog::Walker& wlk, const Blob& keyMin, const Blob& keyMax, const HeightPos& posMin, const HeightPos& posMax) @@ -3107,8 +3136,8 @@ void NodeDB::ContractLogEnum(ContractLog::Walker& wlk, const Blob& keyMin, const wlk.m_Rs.put(0, keyMin); wlk.m_Rs.put(1, keyMax); - put_ContractLogPos(wlk.m_Rs, 2, posMin, wlk.m_bufMin); - put_ContractLogPos(wlk.m_Rs, 3, posMax, wlk.m_bufMax); + wlk.m_bufMin.put(wlk.m_Rs, 2, posMin); + wlk.m_bufMax.put(wlk.m_Rs, 3, posMax); } bool NodeDB::ContractLog::Walker::MoveNext() @@ -3116,46 +3145,64 @@ bool NodeDB::ContractLog::Walker::MoveNext() if (!m_Rs.Step()) return false; - const auto& pos = m_Rs.get_As(0); - pos.m_Height.Export(m_Entry.m_Pos.m_Height); - pos.m_Idx.Export(m_Entry.m_Pos.m_Pos); - + HeightPosPacked::get(m_Rs, 0, m_Entry.m_Pos); m_Rs.get(1, m_Entry.m_Key); m_Rs.get(2, m_Entry.m_Val); return true; } -void NodeDB::KrnInfoInsert(Height h, const Blob& b) +void NodeDB::KrnInfoInsert(const KrnInfo::Entry& x) { - Recordset rs(*this, Query::KrnInfoInsert, "INSERT INTO " TblKrnInfo " (" TblKrnInfo_Key "," TblKrnInfo_Data ") VALUES(?,?)"); - rs.put(0, h); - rs.put(1, b); + Recordset rs(*this, Query::KrnInfoInsert, "INSERT INTO " TblKrnInfo " (" TblKrnInfo_Pos "," TblKrnInfo_Key "," TblKrnInfo_Data ") VALUES(?,?,?)"); + + HeightPosPacked buf; + buf.put(rs, 0, x.m_Pos); + + rs.put(1, x.m_Cid); + rs.put(2, x.m_Val); + rs.Step(); + TestChanged1Row(); } -bool NodeDB::KrnInfoGet(Height h, ByteBuffer& buf) +void NodeDB::KrnInfoDel(const HeightRange& hr) +{ + Recordset rs(*this, Query::KrnInfoDel, "DELETE FROM " TblKrnInfo " WHERE " TblKrnInfo_Pos " BETWEEN ? AND ?"); + + HeightPos posMin(hr.m_Min), posMax(hr.m_Max, static_cast(-1)); + HeightPosPacked bufMin, bufMax; + bufMin.put(rs, 0, posMin); + bufMax.put(rs, 1, posMax); + + rs.Step(); +} + +void NodeDB::KrnInfoEnum(KrnInfo::Walker& wlk, Height h) { - Recordset rs(*this, Query::KrnInfoGet, "SELECT " TblKrnInfo_Data " FROM " TblKrnInfo " WHERE " TblKrnInfo_Key "=?"); - rs.put(0, h); - if (!rs.Step()) - { - buf.clear(); - return false; - } + wlk.m_Rs.Reset(*this, Query::KrnInfoEnumH, "SELECT * FROM " TblKrnInfo " WHERE " TblKrnInfo_Pos " BETWEEN ? AND ? ORDER BY " TblKrnInfo_Pos); - rs.get(0, buf); - return true; + HeightPos posMin(h), posMax(h, static_cast(-1)); + wlk.m_bufMin.put(wlk.m_Rs, 0, posMin); + wlk.m_bufMax.put(wlk.m_Rs, 1, posMax); } -void NodeDB::KrnInfoDel(const HeightRange& hr) +void NodeDB::KrnInfoEnum(KrnInfo::Walker& wlk, const KrnInfo::Cid& cid, Height hMax) { - if (!hr.IsEmpty()) - { - Recordset rs(*this, Query::KrnInfoDel, "DELETE FROM " TblKrnInfo " WHERE " TblKrnInfo_Key ">=? AND " TblKrnInfo_Key "<=?"); - rs.put(0, hr.m_Min); - rs.put(1, hr.m_Max); - rs.Step(); - } + wlk.m_Rs.Reset(*this, Query::KrnInfoEnumCid, "SELECT * FROM " TblKrnInfo + " WHERE (" TblKrnInfo "=?) AND (" TblKrnInfo_Pos "<=?) ORDER BY " TblContractLogs_Pos " DESC"); + wlk.m_Rs.put(0, cid); + wlk.m_bufMax.put(wlk.m_Rs, 1, HeightPos(hMax, static_cast(-1))); +} + +bool NodeDB::KrnInfo::Walker::MoveNext() +{ + if (!m_Rs.Step()) + return false; + + HeightPosPacked::get(m_Rs, 0, m_Entry.m_Pos); + m_Rs.get_As(1, m_Entry.m_Cid); + m_Rs.get(2, m_Entry.m_Val); + return true; } } // namespace beam diff --git a/node/db.h b/node/db.h index f862a7235..92d535851 100644 --- a/node/db.h +++ b/node/db.h @@ -208,7 +208,8 @@ class NodeDB ShieldedStatisticDel, KrnInfoInsert, - KrnInfoGet, + KrnInfoEnumH, + KrnInfoEnumCid, KrnInfoDel, Dbg0, @@ -713,17 +714,18 @@ class NodeDB void StreamsDelAll(StreamType::Enum t0, StreamType::Enum t1); - struct ContractLog - { #pragma pack (push, 1) - struct PosPacked { - uintBigFor::Type m_Height; - uintBigFor::Type m_Idx; - }; + struct HeightPosPacked + { + uintBigFor::Type m_Height; + uintBigFor::Type m_Idx; + void put(NodeDB::Recordset& rs, int iCol, const HeightPos& pos); + static void get(NodeDB::Recordset& rs, int iCol, HeightPos& pos); + }; #pragma pack (pop) - typedef const ECC::Hash::Value Cid; - + struct ContractLog + { struct Entry { HeightPos m_Pos; @@ -733,7 +735,7 @@ class NodeDB struct Walker { - PosPacked m_bufMin, m_bufMax; + HeightPosPacked m_bufMin, m_bufMax; Recordset m_Rs; Entry m_Entry; @@ -746,9 +748,31 @@ class NodeDB void ContractLogEnum(ContractLog::Walker&, const HeightPos& posMin, const HeightPos& posMax); void ContractLogEnum(ContractLog::Walker&, const Blob& keyMin, const Blob& keyMax, const HeightPos& posMin, const HeightPos& posMax); - void KrnInfoInsert(Height, const Blob&); - bool KrnInfoGet(Height, ByteBuffer&); + struct KrnInfo + { + typedef ECC::Hash::Value Cid; + + struct Entry + { + HeightPos m_Pos; + Cid m_Cid; + Blob m_Val; + }; + + struct Walker + { + HeightPosPacked m_bufMin, m_bufMax; + Recordset m_Rs; + Entry m_Entry; + bool MoveNext(); + }; + }; + + + void KrnInfoInsert(const KrnInfo::Entry&); void KrnInfoDel(const HeightRange&); + void KrnInfoEnum(KrnInfo::Walker&, Height); + void KrnInfoEnum(KrnInfo::Walker&, const KrnInfo::Cid&, Height hMax); void TestChanged1Row(); @@ -781,7 +805,8 @@ class NodeDB void CreateTables23(); void CreateTables27(); void CreateTables28(); - void CreateTables29(); + void CreateTables30(); + void CreateTables31(); void ExecQuick(const char*); std::string ExecTextOut(const char*); bool ExecStep(sqlite3_stmt*); diff --git a/node/node.cpp b/node/node.cpp index 29ae0c54a..053be986d 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -3469,6 +3469,7 @@ void Node::Peer::OnMsg(proto::GetProofShieldedInp&& msg) void Node::Peer::OnMsg(proto::GetProofAsset&& msg) { proto::ProofAsset msgOut; + msgOut.m_Info.m_Deposit = Rules::get().CA.DepositForList2; // for backward compatibility, if asset not found - older deserialization should work Processor& p = m_This.m_Processor; if (!p.IsFastSync()) diff --git a/node/processor.cpp b/node/processor.cpp index 23a5898d4..2d33e84d8 100644 --- a/node/processor.cpp +++ b/node/processor.cpp @@ -2423,9 +2423,9 @@ struct NodeProcessor::BlockInterpretCtx virtual Height get_Height() override; virtual bool get_HdrAt(Block::SystemState::Full&) override; - virtual Asset::ID AssetCreate(const Asset::Metadata&, const PeerID&) override; + virtual Asset::ID AssetCreate(const Asset::Metadata&, const PeerID&, Amount& valDeposit) override; virtual bool AssetEmit(Asset::ID, const PeerID&, AmountSigned) override; - virtual bool AssetDestroy(Asset::ID, const PeerID&) override; + virtual bool AssetDestroy(Asset::ID, const PeerID&, Amount& valDeposit) override; BlobMap::Entry* FindVarEx(const Blob& key, bool bExact, bool bBigger); bool EnsureNoVars(const bvm2::ContractID&); @@ -2443,8 +2443,10 @@ struct NodeProcessor::BlockInterpretCtx void ParseExtraInfo(ContractInvokeExtraInfo&, const bvm2::ShaderID&, uint32_t iMethod, const Blob& args); - virtual void CallFar(const bvm2::ContractID&, uint32_t iMethod, Wasm::Word pArgs, uint8_t bInheritContext) override; + virtual void CallFar(const bvm2::ContractID&, uint32_t iMethod, Wasm::Word pArgs, uint32_t nArgs, uint8_t bInheritContext) override; virtual void OnRet(Wasm::Word nRetAddr) override; + + uint32_t m_iCurrentInvokeExtraInfo = 0; }; uint32_t m_ChargePerBlock = bvm2::Limits::BlockCharge; @@ -2472,6 +2474,8 @@ struct NodeProcessor::BlockInterpretCtx void EnsureAssetsUsed(NodeDB&); + void AddKrnInfo(Serializer&, NodeDB& db); + static uint64_t get_AssetEvtIdx(uint32_t nKrnIdx, uint32_t nSubIdx) { return (static_cast(nKrnIdx) << 32) | nSubIdx; } @@ -2919,14 +2923,8 @@ bool NodeProcessor::HandleBlock(const NodeDB::StateID& sid, const Block::SystemS cf.Do(*this, sid.m_Height); - if (!vC.empty()) - { - ser.reset(); - ser & vC; - - SerializeBuffer sb = ser.buffer(); - m_DB.KrnInfoInsert(sid.m_Height, Blob(sb.first, static_cast(sb.second))); - } + if (bic.m_pvC) + bic.AddKrnInfo(ser, m_DB); } else { @@ -3209,6 +3207,7 @@ void NodeProcessor::Recognizer::Recognize(const TxKernelAssetCreate& v, Height h TemporarySwap ts(Cast::NotConst(v).m_MetaData.m_Value, evt.m_Info.m_Metadata.m_Value); evt.m_Info.m_Owner = v.m_Owner; evt.m_Info.m_Value = Zero; + evt.m_Info.m_Deposit = Rules::get().get_DepositForCA(h); AddEvent(h, EventKey::s_IdxKernel + nKrnIdx, evt, key); } @@ -3238,6 +3237,7 @@ void NodeProcessor::Recognizer::Recognize(const TxKernelAssetEmit& v, Height h, evt.m_Info.m_Value = adp.m_Amount; adp.m_LockHeight.Export(evt.m_Info.m_LockHeight); + evt.m_Info.m_Deposit = Rules::get().CA.DepositForList2; // not used anyway AddEvent(h, EventKey::s_IdxKernel + nKrnIdx, evt); } @@ -3253,6 +3253,7 @@ void NodeProcessor::Recognizer::Recognize(const TxKernelAssetDestroy& v, Height evt.m_Info.m_Owner = v.m_Owner; evt.m_Info.m_Value = Zero; + evt.m_Info.m_Deposit = v.get_Deposit(); AddEvent(h, EventKey::s_IdxKernel + nKrnIdx, evt); } @@ -3534,10 +3535,11 @@ void NodeProcessor::InternalAssetDel(Asset::ID nAssetID, bool bMmr) bool NodeProcessor::HandleKernelType(const TxKernelAssetCreate& krn, BlockInterpretCtx& bic) { Asset::ID aid; - return HandleAssetCreate(krn.m_Owner, krn.m_MetaData, bic, aid); + Amount valDeposit; + return HandleAssetCreate(krn.m_Owner, krn.m_MetaData, bic, aid, valDeposit); } -bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metadata& md, BlockInterpretCtx& bic, Asset::ID& aid, uint32_t nSubIdx) +bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metadata& md, BlockInterpretCtx& bic, Asset::ID& aid, Amount& valDeposit, uint32_t nSubIdx) { if (!bic.m_AlreadyValidated) { @@ -3566,6 +3568,7 @@ bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metad ai.m_ID = 0; // auto ai.m_Owner = pidOwner; ai.m_LockHeight = bic.m_Height; + ai.m_Deposit = valDeposit = Rules::get().get_DepositForCA(bic.m_Height); ai.m_Metadata.m_Hash = md.m_Hash; @@ -3611,10 +3614,14 @@ bool NodeProcessor::HandleAssetCreate(const PeerID& pidOwner, const Asset::Metad bool NodeProcessor::HandleKernelType(const TxKernelAssetDestroy& krn, BlockInterpretCtx& bic) { - return HandleAssetDestroy(krn.m_Owner, bic, krn.m_AssetID); + Amount valDeposit = krn.get_Deposit(); + if (!HandleAssetDestroy(krn.m_Owner, bic, krn.m_AssetID, valDeposit, true)) + return false; + + return true; } -bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx& bic, Asset::ID aid, uint32_t nSubIdx) +bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx& bic, Asset::ID aid, Amount& valDeposit, bool bDepositCheck, uint32_t nSubIdx) { if (!bic.m_AlreadyValidated) bic.EnsureAssetsUsed(m_DB); @@ -3637,6 +3644,9 @@ bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx if (ai.m_LockHeight + Rules::get().CA.LockPeriod > bic.m_Height) return false; + if (bDepositCheck && (valDeposit != ai.m_Deposit)) + return false; + assert(bic.m_AssetsUsed); bic.m_AssetsUsed--; } @@ -3649,6 +3659,13 @@ bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx & ai.m_Metadata & ai.m_LockHeight; + if (bic.m_Height >= Rules::get().pForks[5].m_Height) + ser & ai.m_Deposit; + else + assert(Rules::get().CA.DepositForList2 == ai.m_Deposit); + + valDeposit = ai.m_Deposit; + if (!bic.m_Temporary) { NodeDB::AssetEvt evt; @@ -3668,6 +3685,11 @@ bool NodeProcessor::HandleAssetDestroy(const PeerID& pidOwner, BlockInterpretCtx & ai.m_Metadata & ai.m_LockHeight; + if (bic.m_Height >= Rules::get().pForks[5].m_Height) + der & ai.m_Deposit; + else + ai.m_Deposit = Rules::get().CA.DepositForList2; + InternalAssetAdd(ai, !bic.m_SkipDefinition); if (ai.m_ID != aid) @@ -4424,6 +4446,30 @@ void NodeProcessor::BlockInterpretCtx::EnsureAssetsUsed(NodeDB& db) m_AssetsUsed = static_cast(db.ParamIntGetDef(NodeDB::ParamID::AssetsCountUsed)); } +void NodeProcessor::BlockInterpretCtx::AddKrnInfo(Serializer& ser, NodeDB& db) +{ + assert(m_pvC); + auto& vC = *m_pvC; + + for (uint32_t i = 0; i < vC.size(); i++) + { + const auto& info = vC[i]; + + NodeDB::KrnInfo::Entry x; + x.m_Pos.m_Height = m_Height; + x.m_Pos.m_Pos = i + 1; + x.m_Cid = info.m_Cid; + + ser.reset(); + ser & info; + + SerializeBuffer sb = ser.buffer(); + x.m_Val = Blob(sb.first, static_cast(sb.second)); + + db.KrnInfoInsert(x); + } +} + void NodeProcessor::BlockInterpretCtx::AssetEvtInsert(NodeDB& db, NodeDB::AssetEvt& evt, uint32_t nSubIdx) { evt.m_Height = m_Height; @@ -4545,7 +4591,7 @@ bool NodeProcessor::BlockInterpretCtx::BvmProcessor::Invoke(const bvm2::Contract Wasm::Reader::Mode::Restrict : Wasm::Reader::Mode::Emulate_x86; - CallFar(cid, iMethod, m_Stack.get_AlasSp(), 0); + CallFar(cid, iMethod, m_Stack.get_AlasSp(), (uint32_t) krn.m_Args.size(), 0); ECC::Hash::Processor hp; @@ -4715,17 +4761,16 @@ struct NodeProcessor::ProcessorInfoParser m_Height = p.m_Cursor.m_Full.m_Height; } - bool Init() + bool Init(uint32_t nStackBytesExtra) { m_Proc.m_DB.ParamGet(NodeDB::ParamID::RichContractParser, nullptr, nullptr, &m_bufParser); if (m_bufParser.empty()) return false; - InitMem(); + InitMem(nStackBytesExtra); m_Code = m_bufParser; m_pOut = &m_os; - m_RawText = true; return true; } @@ -4761,7 +4806,7 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::ParseExtraInfo(ContractInvo ProcessorInfoParser proc(m_Proc); proc.m_Height = m_Bic.m_Height - 1; - if (!proc.Init()) + if (!proc.Init(m_Stack.AlignUp(args.n))) return; proc.m_Stack.PushAlias(args); @@ -4788,7 +4833,7 @@ void NodeProcessor::get_ContractDescr(const ECC::uintBig& sid, const ECC::uintBi try { ProcessorInfoParser proc(*this); - if (!proc.Init()) + if (!proc.Init(0)) return; proc.PushArgBoth(sid); @@ -5049,10 +5094,10 @@ bool NodeProcessor::get_HdrAt(Block::SystemState::Full& s) return true; } -Asset::ID NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetCreate(const Asset::Metadata& md, const PeerID& pidOwner) +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, m_AssetEvtSubIdx)) + if (!m_Proc.HandleAssetCreate(pidOwner, md, m_Bic, aid, valDeposit, m_AssetEvtSubIdx)) return 0; BlockInterpretCtx::Ser ser(m_Bic); @@ -5080,9 +5125,9 @@ bool NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetEmit(Asset::ID aid, co return true; } -bool NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetDestroy(Asset::ID aid, const PeerID& pidOwner) +bool NodeProcessor::BlockInterpretCtx::BvmProcessor::AssetDestroy(Asset::ID aid, const PeerID& pidOwner, Amount& valDeposit) { - if (!m_Proc.HandleAssetDestroy(pidOwner, m_Bic, aid, m_AssetEvtSubIdx)) + if (!m_Proc.HandleAssetDestroy(pidOwner, m_Bic, aid, valDeposit, false, m_AssetEvtSubIdx)) return false; BlockInterpretCtx::Ser ser(m_Bic); @@ -5116,8 +5161,9 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::UndoVars() Asset::ID aid = 0; PeerID pidOwner; Asset::Metadata md; + Amount valDeposit; - if (!m_Proc.HandleAssetCreate(pidOwner, md, m_Bic, aid)) + if (!m_Proc.HandleAssetCreate(pidOwner, md, m_Bic, aid, valDeposit)) return OnCorrupted(); } break; @@ -5148,7 +5194,8 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::UndoVars() der & aid; der & pidOwner; - if (!m_Proc.HandleAssetDestroy(pidOwner, m_Bic, aid)) + Amount valDeposit; + if (!m_Proc.HandleAssetDestroy(pidOwner, m_Bic, aid, valDeposit, false)) return OnCorrupted(); } break; @@ -5215,21 +5262,18 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::UndoVars() } } -void NodeProcessor::BlockInterpretCtx::BvmProcessor::CallFar(const bvm2::ContractID& cid, uint32_t iMethod, Wasm::Word pArgs, uint8_t bInheritContext) +void NodeProcessor::BlockInterpretCtx::BvmProcessor::CallFar(const bvm2::ContractID& cid, uint32_t iMethod, Wasm::Word pArgs, uint32_t nArgs, uint8_t bInheritContext) { - bvm2::ProcessorContract::CallFar(cid, iMethod, pArgs, bInheritContext); + bvm2::ProcessorContract::CallFar(cid, iMethod, pArgs, nArgs, bInheritContext); if (m_Bic.m_pvC) { - auto* pVec = m_Bic.m_pvC; + auto& vec = *m_Bic.m_pvC; // alias + ContractInvokeExtraInfo& x = vec.emplace_back(); - for (uint32_t i = 1; i < m_FarCalls.m_Stack.size(); i++) - { - assert(!pVec->empty()); - pVec = &pVec->back().m_vNested; - } - - ContractInvokeExtraInfo& x = pVec->emplace_back(); + x.m_iParent = m_iCurrentInvokeExtraInfo; + m_iCurrentInvokeExtraInfo = static_cast(vec.size()); + x.m_NumNested = 0; m_pvSigs = &x.m_vSigs; m_FundsIO.m_Map.swap(x.m_FundsIO.m_Map); @@ -5242,7 +5286,7 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::CallFar(const bvm2::Contrac Blob args; if (nArgsOffs < m_Stack.m_BytesMax) { - args.n = m_Stack.m_BytesMax - nArgsOffs; + args.n = bInheritContext ? (m_Stack.m_BytesMax - nArgsOffs) : nArgs; args.p = reinterpret_cast(m_Stack.m_pPtr) + nArgsOffs; } else @@ -5253,42 +5297,23 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::CallFar(const bvm2::Contrac ParseExtraInfo(x, sid, iMethod, args); - if (x.m_sParsed.empty()) - { - if (m_FarCalls.m_Stack.size() > 1) - args.n = 0; // skip args, we don't know the size, only the high bound. No need to print all this. - x.SetUnk(iMethod, args, &sid); - } + // skip args for inherited-context calls, we don't know the size, only the high bound. No need to save all this. + if (bInheritContext) + args.n = 0; + + x.SetUnk(iMethod, args, &sid); } } -void NodeProcessor::ContractInvokeExtraInfo::SetUnk(uint32_t iMethod, const Blob& args, const ECC::uintBig* pSid) +void NodeProcessor::ContractInvokeExtraInfoBase::SetUnk(uint32_t iMethod, const Blob& args, const ECC::uintBig* pSid) { - std::ostringstream os; - - switch (iMethod) + m_iMethod = iMethod; + if (m_sParsed.empty()) { - case 0: - os << "Create"; + args.Export(m_Args); if (pSid) - os << ", Sid=" << *pSid; - break; - - case 1: - os << "Destroy"; - break; - - default: - os << "Method_" << iMethod; - } - - if (args.n) - { - os << ", Args="; - uintBigImpl::_PrintFull(reinterpret_cast(args.p), args.n, os); + m_Sid.reset(*pSid); } - - m_sParsed = os.str(); } void NodeProcessor::BlockInterpretCtx::BvmProcessor::OnRet(Wasm::Word nRetAddr) @@ -5297,21 +5322,15 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::OnRet(Wasm::Word nRetAddr) if (m_Bic.m_pvC && !nRetAddr) { - std::vector* pVcPrev = nullptr; - - auto* pVec = m_Bic.m_pvC; - assert(pVec); + auto& vec = *m_Bic.m_pvC; // alias - for (uint32_t i = 0; i < m_FarCalls.m_Stack.size(); i++) - { - pVcPrev = pVec; + assert(m_iCurrentInvokeExtraInfo <= vec.size()); + auto& x = vec[m_iCurrentInvokeExtraInfo - 1]; - assert(!pVec->empty()); - pVec = &pVec->back().m_vNested; - } - - assert(!pVec->empty()); - ContractInvokeExtraInfo& x = pVec->back(); + m_iCurrentInvokeExtraInfo = x.m_iParent; + ContractInvokeExtraInfo* pParent = x.m_iParent ? &vec[x.m_iParent - 1] : nullptr; + if (pParent) + pParent->m_NumNested += x.m_NumNested + 1; if (x.m_FundsIO.m_Map.empty()) x.m_FundsIO = m_FundsIO; // save it @@ -5324,7 +5343,7 @@ void NodeProcessor::BlockInterpretCtx::BvmProcessor::OnRet(Wasm::Word nRetAddr) m_FundsIO.Add(it->second, it->first); } - m_pvSigs = pVcPrev ? &pVcPrev->back().m_vSigs : nullptr; + m_pvSigs = pParent ? &pParent->m_vSigs : nullptr; } } @@ -6416,11 +6435,14 @@ bool NodeProcessor::ExtractBlockWithExtra(Block::Body& block, std::vector* m_pvC = nullptr; KrnWalkerRebuild(NodeProcessor& p) :m_This(p) {} ByteBuffer m_Rollback; @@ -6878,9 +6901,7 @@ void NodeProcessor::RebuildNonStd() m_pBic = &bic; BlockInterpretCtx::ChangesFlush cf(m_This); - std::vector vC; - m_pBic->m_pvC = &vC; - + m_pBic->m_pvC = m_pvC; bic.m_AlreadyValidated = true; bic.EnsureAssetsUsed(m_This.get_DB()); bic.SetAssetHi(m_This); @@ -6893,16 +6914,17 @@ void NodeProcessor::RebuildNonStd() cf.Do(m_This, m_Height); - if (!vC.empty()) + if (m_pvC) { Serializer ser; ser.swap_buf(m_Rollback); - ser & vC; - ser.swap_buf(m_Rollback); - m_This.m_DB.KrnInfoInsert(m_Height, m_Rollback); + bic.AddKrnInfo(ser, m_This.m_DB); + + ser.swap_buf(m_Rollback); m_Rollback.clear(); + m_pvC->clear(); } return true; @@ -6920,6 +6942,9 @@ void NodeProcessor::RebuildNonStd() } wlk(*this); + std::vector vC; + wlk.m_pvC = m_DB.ParamIntGetDef(NodeDB::ParamID::RichContractInfo) ? &vC : nullptr; + EnumKernels(wlk, HeightRange(Rules::get().pForks[2].m_Height, m_Cursor.m_ID.m_Height)); } @@ -6946,6 +6971,8 @@ int NodeProcessor::get_AssetAt(Asset::Full& ai, Height h) memcpy(&ai.m_Metadata.m_Value.front(), pAcip + 1, ai.m_Metadata.m_Value.size()); ai.m_Metadata.UpdateHash(); + ai.m_Deposit = Rules::get().get_DepositForCA(wlk.m_Height); + typedef std::pair HeightAndIndex; HeightAndIndex hiCreate(wlk.m_Height, wlk.m_Index); diff --git a/node/processor.h b/node/processor.h index c331b8724..12aae0e79 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&, uint32_t nSubIdx = 0); + bool HandleAssetCreate(const PeerID&, 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, uint32_t nSubIdx = 0); + bool HandleAssetDestroy(const PeerID&, BlockInterpretCtx&, Asset::ID, Amount& valDeposit, bool bDepositCheck, uint32_t nSubIdx = 0); bool HandleKernel(const TxKernel&, BlockInterpretCtx&); bool HandleKernelTypeAny(const TxKernel&, BlockInterpretCtx&); @@ -404,14 +404,16 @@ class NodeProcessor void SaveSyncData(); void LogSyncData(); - struct ContractInvokeExtraInfo + struct ContractInvokeExtraInfoBase { - ECC::uintBig m_Cid; - FundsChangeMap m_FundsIO; // including nested std::vector m_vSigs; // excluding nested - std::vector m_vNested; + uint32_t m_iParent; // including sub-nested + uint32_t m_NumNested; std::string m_sParsed; + uint32_t m_iMethod; + ByteBuffer m_Args; + boost::optional m_Sid; void SetUnk(uint32_t iMethod, const Blob& args, const ECC::uintBig* pSid); @@ -419,14 +421,23 @@ class NodeProcessor void serialize(Archive& ar) { ar - & m_Cid + & m_Sid & m_FundsIO.m_Map & m_vSigs - & m_vNested + & m_iParent + & m_NumNested + & m_iMethod + & m_Args & m_sParsed; } }; + struct ContractInvokeExtraInfo + :public ContractInvokeExtraInfoBase + { + ECC::uintBig m_Cid; + }; + bool ExtractBlockWithExtra(Block::Body&, std::vector& vOutsIn, const NodeDB::StateID&, std::vector&); void get_ContractDescr(const ECC::uintBig& sid, const ECC::uintBig& cid, std::string&, bool bFullState); diff --git a/node/unittests/node_test.cpp b/node/unittests/node_test.cpp index b98a16941..a2bca4a10 100644 --- a/node/unittests/node_test.cpp +++ b/node/unittests/node_test.cpp @@ -2307,15 +2307,15 @@ namespace beam if (m_Assets.m_hCreated) return false; - const Amount nFee = 330; - Amount nLock = Rules::get().CA.DepositForList; - if (val < nLock + nFee) - return false; - const Block::SystemState::Full& s = m_vStates.back(); if (s.m_Height + 1 < Rules::get().pForks[2].m_Height) return false; + const Amount nFee = 330; + Amount nLock = Rules::get().get_DepositForCA(s.m_Height + 1); + if (val < nLock + nFee) + return false; + val -= nLock + nFee; ECC::Scalar::Native sk; @@ -3880,7 +3880,7 @@ void TestAll() beam::Rules::get().pForks[2].m_Height = 17; beam::Rules::get().pForks[3].m_Height = 17; beam::Rules::get().pForks[4].m_Height = 17; - beam::Rules::get().CA.DepositForList = beam::Rules::Coin * 16; + beam::Rules::get().CA.DepositForList2 = beam::Rules::Coin * 16; beam::Rules::get().CA.LockPeriod = 2; beam::Rules::get().Shielded.m_ProofMax = { 4, 6 }; // 4K beam::Rules::get().Shielded.m_ProofMin = { 4, 5 }; // 1K diff --git a/utility/cli/options.cpp b/utility/cli/options.cpp index a90574b11..c1b7a40d1 100644 --- a/utility/cli/options.cpp +++ b/utility/cli/options.cpp @@ -716,7 +716,8 @@ namespace beam macro(bool, FakePoW, "Don't verify PoW. Mining is simulated by the timer. For tests only") \ macro(Height, MaxKernelValidityDH, "Max implicit kernel lifespan after HF2 (a.k.a. kernel visibility horizon)") \ macro(bool, CA.Enabled, "Enable/disable CA (confidential assets)") \ - macro(Amount, CA.DepositForList, "Deposit for new CA allocation") \ + macro(Amount, CA.DepositForList2, "Deposit for new CA allocation since HF2") \ + macro(Amount, CA.DepositForList5, "Deposit for new CA allocation since HF5") \ macro(Height, CA.LockPeriod, "Lock height for deposit after the CA is completely burned") \ macro(uint32_t, CA.m_ProofCfg.n, "Asset type anonymity set size n (n^M)") \ macro(uint32_t, CA.m_ProofCfg.M, "Asset type anonymity set size M (n^M)") \ diff --git a/version.h.in b/version.h.in index b1b438c19..828a07117 100644 --- a/version.h.in +++ b/version.h.in @@ -3,9 +3,9 @@ inline constexpr unsigned VERSION_MAJOR = @VERSION_MAJOR@; inline constexpr unsigned VERSION_MINOR = @VERSION_MINOR@; inline constexpr unsigned VERSION_REVISION = @VERSION_REVISION@; -inline constexpr std::string_view GIT_COMMIT_HASH = "@GIT_COMMIT_HASH@"; -inline constexpr std::string_view PROJECT_VERSION = "@PROJECT_VERSION@"; -inline constexpr std::string_view BRANCH_NAME = "@BRANCH_NAME@"; +inline const std::string GIT_COMMIT_HASH = "@GIT_COMMIT_HASH@"; +inline const std::string PROJECT_VERSION = "@PROJECT_VERSION@"; +inline const std::string BRANCH_NAME = "@BRANCH_NAME@"; #ifndef BEAM_LIB_VERSION #define BEAM_LIB_VERSION "@PROJECT_VERSION@" diff --git a/wallet/api/cli/api_cli.cpp b/wallet/api/cli/api_cli.cpp index d15fa8b09..3e83d46ed 100644 --- a/wallet/api/cli/api_cli.cpp +++ b/wallet/api/cli/api_cli.cpp @@ -305,7 +305,7 @@ namespace _walletData->walletDB = _walletDB; _walletData->wallet = _wallet; _walletData->acl = _acl; - _walletData->contracts = IShadersManager::CreateInstance(_wallet, _walletDB, _network, "", ""); + _walletData->contracts = IShadersManager::CreateInstance(_wallet, _walletDB, _network, "", "", 0); _walletData->nodeNetwork = _network; #ifdef BEAM_ATOMIC_SWAP_SUPPORT diff --git a/wallet/cli/cli.cpp b/wallet/cli/cli.cpp index 755ffc549..d60ae1756 100644 --- a/wallet/cli/cli.cpp +++ b/wallet/cli/cli.cpp @@ -2044,7 +2044,6 @@ namespace } auto params = CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, Rules::get().CA.DepositForList) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::PreselectedCoins, GetPreselectedCoinIDs(vm)) .SetParameter(TxParameterID::AssetMetadata, strMeta); @@ -2077,7 +2076,6 @@ namespace } auto params = CreateTransactionParameters(TxType::AssetUnreg) - .SetParameter(TxParameterID::Amount, Rules::get().CA.DepositForList) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::PreselectedCoins, GetPreselectedCoinIDs(vm)) .SetParameter(TxParameterID::AssetMetadata, meta); diff --git a/wallet/client/apps_api/apps_api.h b/wallet/client/apps_api/apps_api.h index 39ae7355a..494d83a52 100644 --- a/wallet/client/apps_api/apps_api.h +++ b/wallet/client/apps_api/apps_api.h @@ -47,7 +47,6 @@ namespace beam::wallet , _client(nullptr) { _walletAPIProxy = std::make_shared(); - LOG_INFO () << "AppsApi created for " << _appName << ", " << _appId; } ~AppsApi() override @@ -74,6 +73,7 @@ namespace beam::wallet std::string version, std::string appid, std::string appname, + uint32_t privilegeLvl, bool ipfsnode, std::function cback) { @@ -92,7 +92,7 @@ namespace beam::wallet }; client->getAsync()->makeIWTCall( - [client, appid, appname, ipfsnode]() -> boost::any { + [client, appid, appname, privilegeLvl, ipfsnode]() -> boost::any { // // THIS IS WALLET CLIENT REACTOR THREAD // @@ -121,10 +121,10 @@ namespace beam::wallet << appname << "' DApp"; } - result.shaders = client->IWThread_createAppShaders(appid, appname); + result.shaders = client->IWThread_createAppShaders(appid, appname, privilegeLvl); return result; }, - [client, cback=std::move(cback), version, appid, appname](boost::any aptr) { + [client, cback=std::move(cback), version, appid, appname, privilegeLvl](boost::any aptr) { // // THIS IS UI THREAD // @@ -148,6 +148,7 @@ namespace beam::wallet #endif wapi->_walletAPI = IWalletApi::CreateInstance(version, *wapi->_walletAPIProxy, data); + LOG_INFO () << "AppsApi created for " << appid << ", " << appname << ", privileges " << privilegeLvl; cback(std::move(wapi)); } ); diff --git a/wallet/client/wallet_client.cpp b/wallet/client/wallet_client.cpp index 9c757d96b..300b2b8f7 100644 --- a/wallet/client/wallet_client.cpp +++ b/wallet/client/wallet_client.cpp @@ -41,7 +41,7 @@ namespace using namespace beam; using namespace beam::wallet; -constexpr size_t kCollectorBufferSize = 50; +constexpr size_t kCollectorBufferSize = 100; constexpr size_t kShieldedPer24hFilterSize = 20; constexpr size_t kShieldedPer24hFilterBlocksForUpdate = 144; constexpr size_t kShieldedCountHistoryWindowSize = kShieldedPer24hFilterSize << 1; @@ -760,7 +760,7 @@ namespace beam::wallet // // Shaders // - auto clientShaders = IShadersManager::CreateInstance(wallet, m_walletDB, nodeNetwork, "", ""); + auto clientShaders = IShadersManager::CreateInstance(wallet, m_walletDB, nodeNetwork, "", "", 0); _clientShaders = clientShaders; nodeNetwork->tryToConnect(); @@ -954,12 +954,12 @@ namespace beam::wallet } #endif //BEAM_IPFS_SUPPORT - IShadersManager::Ptr WalletClient::IWThread_createAppShaders(const std::string& appid, const std::string& appname) + IShadersManager::Ptr WalletClient::IWThread_createAppShaders(const std::string& appid, const std::string& appname, uint32_t privilegeLvl) { auto wallet = m_wallet.lock(); auto network = m_nodeNetwork.lock(); assert(wallet && network); - return IShadersManager::CreateInstance(wallet, m_walletDB, network, appid, appname); + return IShadersManager::CreateInstance(wallet, m_walletDB, network, appid, appname, privilegeLvl); } std::string WalletClient::getNodeAddress() const @@ -1450,23 +1450,23 @@ namespace beam::wallet void WalletClient::getTransactionsSmoothly() { - auto txCount = m_walletDB->getTxCount(wallet::TxType::ALL); - if (txCount > kOneTimeLoadTxCount) - { - onTransactionChanged(ChangeAction::Reset, vector()); - - auto iterationsCount = txCount / kOneTimeLoadTxCount + (txCount % kOneTimeLoadTxCount ? 1 : 0); - for(int i = 0; i < iterationsCount; ++i) - onTransactionChanged( - ChangeAction::Updated, - m_walletDB->getTxHistory(wallet::TxType::ALL, - i * kOneTimeLoadTxCount, - i * kOneTimeLoadTxCount + kOneTimeLoadTxCount)); - } - else - { + //auto txCount = m_walletDB->getTxCount(wallet::TxType::ALL); + //if (txCount > kOneTimeLoadTxCount) + //{ + // onTransactionChanged(ChangeAction::Reset, vector()); + + // auto iterationsCount = txCount / kOneTimeLoadTxCount + (txCount % kOneTimeLoadTxCount ? 1 : 0); + // for(int i = 0; i < iterationsCount; ++i) + // onTransactionChanged( + // ChangeAction::Added, + // m_walletDB->getTxHistory(wallet::TxType::ALL, + // i * kOneTimeLoadTxCount, + // i * kOneTimeLoadTxCount + kOneTimeLoadTxCount)); + //} + //else + //{ getTransactions(); - } + //} } void WalletClient::getAllUtxosStatus() diff --git a/wallet/client/wallet_client.h b/wallet/client/wallet_client.h index 4555af696..4e5dcc532 100644 --- a/wallet/client/wallet_client.h +++ b/wallet/client/wallet_client.h @@ -136,7 +136,7 @@ namespace beam::wallet void IWThread_stopIPFSNode(); // throws on fail; #endif - IShadersManager::Ptr IWThread_createAppShaders(const std::string& appid, const std::string& appname); + IShadersManager::Ptr IWThread_createAppShaders(const std::string& appid, const std::string& appname, uint32_t privilegeLvl); std::string getNodeAddress() const; std::string exportOwnerKey(const beam::SecString& pass) const; diff --git a/wallet/core/common.h b/wallet/core/common.h index 12efe2444..6d7589296 100644 --- a/wallet/core/common.h +++ b/wallet/core/common.h @@ -174,7 +174,7 @@ namespace beam::wallet MACRO(AssetConfirmFailed, 32, "Failed to receive asset confirmation") \ MACRO(AssetInUse, 33, "Asset is still in use (issued amount > 0)") \ MACRO(AssetLocked, 34, "Asset is still locked") \ - MACRO(RegisterAmountTooSmall, 35, "Asset registration fee is too small") \ + /*MACRO(RegisterAmountTooSmall, 35, "Asset registration fee is too small")*/ \ MACRO(ICAmountTooBig, 36, "Cannot issue/consume more than MAX_INT64 asset groth in one transaction") \ MACRO(NotEnoughDataForProof, 37, "Some mandatory data for payment proof is missing") \ MACRO(NoMasterKey, 38, "Master key is needed for this transaction, but unavailable") \ diff --git a/wallet/core/contracts/i_shaders_manager.h b/wallet/core/contracts/i_shaders_manager.h index d03d6bdb5..5afee2fc6 100644 --- a/wallet/core/contracts/i_shaders_manager.h +++ b/wallet/core/contracts/i_shaders_manager.h @@ -34,7 +34,8 @@ namespace beam::wallet beam::wallet::IWalletDB::Ptr wdb, beam::proto::FlyClient::INetwork::Ptr nodeNetwork, std::string appid, - std::string appname); + std::string appname, + uint32_t privilegeLvl); virtual ~IShadersManager() = default; diff --git a/wallet/core/contracts/shaders_manager.cpp b/wallet/core/contracts/shaders_manager.cpp index 3e4f29d00..8bea94c94 100644 --- a/wallet/core/contracts/shaders_manager.cpp +++ b/wallet/core/contracts/shaders_manager.cpp @@ -160,14 +160,16 @@ namespace beam::wallet { beam::wallet::IWalletDB::Ptr walletDB, beam::proto::FlyClient::INetwork::Ptr nodeNetwork, std::string appid, - std::string appname) - :ManagerStdInWallet(std::move(walletDB), wallet) + std::string appname, + uint32_t privilegeLvl) + : ManagerStdInWallet(std::move(walletDB), wallet) , _currentAppId(std::move(appid)) , _currentAppName(std::move(appname)) , _wallet(std::move(wallet)) { assert(_wallet); _logResult = appid.empty(); + set_Privilege(privilegeLvl); } void ShadersManager::compileAppShader(const std::vector &shader) @@ -430,14 +432,16 @@ namespace beam::wallet { beam::wallet::IWalletDB::Ptr wdb, beam::proto::FlyClient::INetwork::Ptr nodeNetwork, std::string appid, - std::string appname) + std::string appname, + uint32_t privilegeLvl) { return std::make_shared( std::move(wallet), std::move(wdb), std::move(nodeNetwork), std::move(appid), - std::move(appname) - ); + std::move(appname), + privilegeLvl + ); } } diff --git a/wallet/core/contracts/shaders_manager.h b/wallet/core/contracts/shaders_manager.h index ea96a3b6a..5c971e9a3 100644 --- a/wallet/core/contracts/shaders_manager.h +++ b/wallet/core/contracts/shaders_manager.h @@ -46,11 +46,6 @@ namespace beam::wallet { void WriteStream(const Blob&, uint32_t iStream) override; }; - - - - - class ShadersManager : public IShadersManager , private ManagerStdInWallet @@ -60,7 +55,8 @@ namespace beam::wallet { beam::wallet::IWalletDB::Ptr walletDB, beam::proto::FlyClient::INetwork::Ptr nodeNetwork, std::string appid, - std::string appname); + std::string appname, + uint32_t privilegeLvl); bool IsDone() const override { diff --git a/wallet/core/wallet_db.cpp b/wallet/core/wallet_db.cpp index a41c8ed29..e0c9ec79c 100644 --- a/wallet/core/wallet_db.cpp +++ b/wallet/core/wallet_db.cpp @@ -169,7 +169,7 @@ namespace fs = std::filesystem; #define LASER_CHANNEL_FIELDS ENUM_LASER_CHANNEL_FIELDS(LIST, COMMA, ) -#define ENUM_ASSET_FIELDS(each, sep, obj) \ +#define ENUM_ASSET_FIELDS_0(each, sep, obj) \ each(ID, ID, INTEGER NOT NULL PRIMARY KEY, obj) sep \ each(Value, Value, BLOB, obj) sep \ each(Owner, Owner, BLOB NOT NULL, obj) sep \ @@ -178,6 +178,10 @@ namespace fs = std::filesystem; each(RefreshHeight, RefreshHeight, INTEGER NOT NULL, obj) sep \ each(IsOwned, IsOwned, INTEGER, obj) +#define ENUM_ASSET_FIELDS(each, sep, obj) \ + ENUM_ASSET_FIELDS_0(each, sep, obj) sep \ + each(Deposit, Deposit, INTEGER, obj) + #define ASSET_FIELDS ENUM_ASSET_FIELDS(LIST, COMMA, ) #define ENUM_SHIELDED_COIN_FIELDS(each, sep, obj) \ @@ -992,7 +996,8 @@ namespace beam::wallet const uint8_t kDefaultMaxPrivacyLockTimeLimitHours = 72; const int BusyTimeoutMs = 5000; - const int DbVersion = 32; + const int DbVersion = 33; + const int DbVersion32 = 32; const int DbVersion31 = 31; const int DbVersion30 = 30; const int DbVersion29 = 29; @@ -1346,7 +1351,7 @@ namespace beam::wallet // migration { - const char* req = "INSERT INTO " ASSETS_NAME " (" ENUM_ASSET_FIELDS(LIST, COMMA, ) ") SELECT " ENUM_ASSET_FIELDS(LIST, COMMA, ) " FROM " ASSETS_NAME "_del;"; + const char* req = "INSERT INTO " ASSETS_NAME " (" ENUM_ASSET_FIELDS_0(LIST, COMMA, ) ") SELECT " ENUM_ASSET_FIELDS_0(LIST, COMMA, ) " FROM " ASSETS_NAME "_del;"; int ret = sqlite3_exec(db, req, NULL, NULL, NULL); throwIfError(ret, db); } @@ -1725,6 +1730,19 @@ namespace beam::wallet } } + void MigrateFrom32(sqlite3* db) + { + assert(db != nullptr); + + // assets table changed: added Deposit column + // move old data to temp table + { + const char* req = "ALTER TABLE " ASSETS_NAME " ADD COLUMN Deposit INTEGER;"; + int ret = sqlite3_exec(db, req, NULL, NULL, NULL); + throwIfError(ret, db); + } + } + void OpenAndMigrateIfNeeded(const string& path, sqlite3** db, const SecString& password) { int ret = sqlite3_open_v2(path.c_str(), db, SQLITE_OPEN_READWRITE, nullptr); @@ -2366,6 +2384,12 @@ namespace beam::wallet LOG_INFO() << "Converting DB from format 31..."; MigrateFrom31(walletDB.get(), walletDB->_db); // no break + + case DbVersion32: + LOG_INFO() << "Converting DB from format 32..."; + MigrateFrom32(walletDB->_db); + + // no break storage::setVar(*walletDB, Version, DbVersion); case DbVersion: @@ -4342,7 +4366,7 @@ namespace beam::wallet sqlite::Statement stmFind(this, find); stmFind.bind(1, info.m_ID); - const char* update = "UPDATE " ASSETS_NAME " SET Value=?2, Owner=?3, LockHeight=?4, Metadata=?5, RefreshHeight=?6 WHERE ID=?1;"; + const char* update = "UPDATE " ASSETS_NAME " SET Value=?2, Owner=?3, LockHeight=?4, Metadata=?5, RefreshHeight=?6, Deposit=?7 WHERE ID=?1;"; const char* insert = "INSERT INTO " ASSETS_NAME " (" ENUM_ASSET_FIELDS(LIST, COMMA, ) ") VALUES(" ENUM_ASSET_FIELDS(BIND_LIST, COMMA, ) ");"; const bool found = stmFind.step(); @@ -4354,11 +4378,14 @@ namespace beam::wallet stm.bind(5, info.m_Metadata.m_Value); stm.bind(6, refreshHeight); - if (!found) + if (found) + stm.bind(7, info.m_Deposit); + else { // By default we do not mark new assets as owned // For owned assets this value is set to the owner index by the 'AssetRegister' transaction stm.bind(7, 0); + stm.bind(8, info.m_Deposit); } stm.step(); @@ -4443,6 +4470,11 @@ namespace beam::wallet assert(asset.m_RefreshHeight != 0); stmFind.get(6, asset.m_IsOwned); + if (stmFind.IsNull(7)) + asset.m_Deposit = Rules::get().CA.DepositForList2; // assume it's legacy + else + stmFind.get(7, asset.m_Deposit); + return asset; } diff --git a/wallet/ipfs/ipfs_imp.cpp b/wallet/ipfs/ipfs_imp.cpp index 76db39b5d..ee6768e2a 100644 --- a/wallet/ipfs/ipfs_imp.cpp +++ b/wallet/ipfs/ipfs_imp.cpp @@ -127,7 +127,7 @@ namespace beam::wallet::imp if (config.swarm_key.empty()) { #if defined(BEAM_TESTNET) - config.swarm_key = "/key/swarm/psk/1.0.0/\n/base16/\n1191aea7c9f99f679f477411d9d44f1ea0fdf5b42d995966b14a9000432f8c4a" + config.swarm_key = "/key/swarm/psk/1.0.0/\n/base16/\n1191aea7c9f99f679f477411d9d44f1ea0fdf5b42d995966b14a9000432f8c4a"; LOG_INFO() << "Default TESTNET IPFS swarm key would be used"; #elif defined(BEAM_MAINNET) config.swarm_key = "/key/swarm/psk/1.0.0/\n/base16/\n1fabcf9eb018710a93a85214809b91a78b8ef5c49f84a5f72da3dff587b0aed5"; diff --git a/wallet/transactions/assets/aregister_transaction.cpp b/wallet/transactions/assets/aregister_transaction.cpp index 05640d1d5..feb4d9426 100644 --- a/wallet/transactions/assets/aregister_transaction.cpp +++ b/wallet/transactions/assets/aregister_transaction.cpp @@ -66,11 +66,6 @@ namespace beam::wallet MyBuilder(AssetRegisterTransaction& tx) :Builder(tx, kDefaultSubTxID) { - const auto amount = GetParameterStrict(TxParameterID::Amount); - if (amount < Rules::get().CA.DepositForList) - { - throw TransactionFailedException(!m_Tx.IsInitiator(), TxFailureReason::RegisterAmountTooSmall); - } } void Sign() @@ -96,10 +91,12 @@ namespace beam::wallet auto& builder = *_builder; + Amount valDeposit = Rules::get().get_DepositForCA(builder.m_Height.m_Min); + if (builder.m_Coins.IsEmpty()) { BaseTxBuilder::Balance bb(builder); - bb.m_Map[0].m_Value -= (Rules::get().CA.DepositForList + builder.m_Fee); + bb.m_Map[0].m_Value -= (valDeposit + builder.m_Fee); bb.CompleteBalance(); builder.SaveCoins(); @@ -117,7 +114,7 @@ namespace beam::wallet builder.Sign(); LOG_INFO() << GetTxID() << " Registering asset with the owner ID " << builder.m_pKrn->CastTo_AssetCreate().m_Owner - << ". Cost is " << PrintableAmount(Rules::get().CA.DepositForList, false) + << ". Cost is " << PrintableAmount(valDeposit, false) << ". Fee is " << PrintableAmount(builder.m_Fee, false); } diff --git a/wallet/transactions/assets/aunregister_transaction.cpp b/wallet/transactions/assets/aunregister_transaction.cpp index b8b618479..22985ad04 100644 --- a/wallet/transactions/assets/aunregister_transaction.cpp +++ b/wallet/transactions/assets/aunregister_transaction.cpp @@ -60,7 +60,7 @@ namespace beam::wallet { using Builder::Builder; - void Sign() + void Sign(Amount valDeposit) { if (m_pKrn) return; @@ -68,6 +68,9 @@ namespace beam::wallet std::unique_ptr pKrn = std::make_unique(); pKrn->m_AssetID = m_Tx.GetMandatoryParameter(TxParameterID::AssetID); + if (m_Height.m_Min >= Rules::get().pForks[5].m_Height) + pKrn->m_Deposit = valDeposit; + AddKernel(std::move(pKrn)); FinalyzeTx(); } @@ -89,12 +92,21 @@ namespace beam::wallet _builder = std::make_shared(*this, kDefaultSubTxID); auto& builder = *_builder; + auto pInfo = GetWalletDB()->findAsset(builder.m_pidAsset); + if (!pInfo) + { + OnFailed(TxFailureReason::NoAssetInfo); + return; + } + + WalletAsset& wa = *pInfo; + if (GetState() == State::Initial) { LOG_INFO() << GetTxID() << " Unregistering asset with the owner id " << builder.m_pidAsset - << ". Refund amount is " << PrintableAmount(Rules::get().CA.DepositForList, false); + << ". Refund amount is " << PrintableAmount(wa.m_Deposit, false); UpdateTxDescription(TxStatus::InProgress); } @@ -119,14 +131,6 @@ namespace beam::wallet return; } - auto pInfo = GetWalletDB()->findAsset(builder.m_pidAsset); - if (!pInfo) - { - OnFailed(TxFailureReason::NoAssetInfo); - return; - } - - WalletAsset& wa = *pInfo; SetParameter(TxParameterID::AssetID, wa.m_ID); if (wa.m_Value != Zero) @@ -143,7 +147,7 @@ namespace beam::wallet } BaseTxBuilder::Balance bb(builder); - bb.m_Map[0].m_Value += Rules::get().CA.DepositForList - builder.m_Fee; + bb.m_Map[0].m_Value += wa.m_Deposit - builder.m_Fee; bb.CompleteBalance(); builder.SaveCoins(); @@ -154,7 +158,7 @@ namespace beam::wallet return; if (!builder.m_pKrn) - builder.Sign(); + builder.Sign(pInfo->m_Deposit); auto registered = proto::TxStatus::Unspecified; if (!GetParameter(TxParameterID::TransactionRegistered, registered)) diff --git a/wallet/unittests/swap_test.cpp b/wallet/unittests/swap_test.cpp index 47d221b3a..219eeae27 100644 --- a/wallet/unittests/swap_test.cpp +++ b/wallet/unittests/swap_test.cpp @@ -2073,8 +2073,7 @@ int main() beam::Height fork1Height = 10; Rules::get().pForks[1].m_Height = fork1Height; Rules::get().pForks[2].m_Height = fork1Height; - Rules::get().pForks[3].m_Height = MaxHeight; // swap values currently specified in the test are insufficient for fees after HF3 - Rules::get().pForks[4].m_Height = MaxHeight; + Rules::get().DisableForksFrom(3); // swap values currently specified in the test are insufficient for fees after HF3 Rules::get().UpdateChecksum(); TestSwapTransaction(true, fork1Height); diff --git a/wallet/unittests/wallet_assets_test.cpp b/wallet/unittests/wallet_assets_test.cpp index 27221fce5..50c6f225c 100644 --- a/wallet/unittests/wallet_assets_test.cpp +++ b/wallet/unittests/wallet_assets_test.cpp @@ -127,9 +127,9 @@ void TestAssets() { const auto mined = AmountBig::get_Lo(totals.GetBeamTotals().Avail); LOG_INFO() << "Beam mined " << PrintableAmount(mined); - const auto deposit = Rules::get().CA.DepositForList; + const auto deposit = Rules::get().CA.DepositForList2; const auto fee = Amount(100); - const auto initial = Rules::get().CA.DepositForList * 2 + fee * 40; // 40 should be enough; + const auto initial = Rules::get().CA.DepositForList2 * 2 + fee * 40; // 40 should be enough; LOG_INFO() << "Beam necessary for test " << PrintableAmount(initial); WALLET_CHECK(initial <= mined); @@ -188,7 +188,6 @@ void TestAssets() { // runTest("assets flag is false", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, beam::Amount(0)) .SetParameter(TxParameterID::Fee, beam::Amount(100)) .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); }); @@ -203,7 +202,6 @@ void TestAssets() { // not enough beam runTest("register, not enough BEAM", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, Rules::get().CA.DepositForList) .SetParameter(TxParameterID::Fee, beam::Amount(100)) .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); }); @@ -220,16 +218,6 @@ void TestAssets() { }, 2, false); LOG_INFO() << "Now owner has " << PrintableAmount(storage::Totals(*ownerDB, false).GetBeamTotals().Avail); - // amount too small - runTest("register, amount is too small", [&] { - return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, beam::Amount(0)) - .SetParameter(TxParameterID::Fee, beam::Amount(100)) - .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); - }); - WALLET_CHECK(tx.m_status == TxStatus::Failed); - WALLET_CHECK(tx.m_failureReason == TxFailureReason::RegisterAmountTooSmall); - // fee too small // TODO: Uncomment when we'll create base builder that checks fees. Now it is assumed to be checked by the CLI // @@ -245,7 +233,6 @@ void TestAssets() { // missing meta runTest("register, missing meta", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, beam::Amount(Rules::get().CA.DepositForList)) .SetParameter(TxParameterID::Fee, beam::Amount(100))); }); WALLET_CHECK(tx.m_status == TxStatus::Failed); @@ -254,7 +241,6 @@ void TestAssets() { // empty meta runTest("register, empty meta", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, beam::Amount(Rules::get().CA.DepositForList)) .SetParameter(TxParameterID::Fee, beam::Amount(100)) .SetParameter(TxParameterID::AssetMetadata, "")); }); @@ -269,14 +255,12 @@ void TestAssets() { runTest("register asset #1", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); }); currBM -= deposit + fee; WALLET_CHECK(tx.m_status == TxStatus::Completed); - WALLET_CHECK(tx.m_amount == deposit); WALLET_CHECK(tx.m_fee == fee); WALLET_CHECK(tx.m_assetId == ASSET1_ID); WALLET_CHECK(tx.m_peerId == Zero); @@ -287,7 +271,6 @@ void TestAssets() { // second time register the same asset runTest("register asset #1 second time", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); }); @@ -300,7 +283,6 @@ void TestAssets() { // successfully register asset #2 runTest("register asset #2", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetReg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET2_META)); }); @@ -308,7 +290,6 @@ void TestAssets() { currBM -= deposit + fee; checkOwnerTotals(currBM, currA1, currA2); WALLET_CHECK(tx.m_status == TxStatus::Completed); - WALLET_CHECK(tx.m_amount == deposit); WALLET_CHECK(tx.m_fee == fee); WALLET_CHECK(tx.m_assetId == ASSET2_ID); WALLET_CHECK(tx.m_peerId == Zero); @@ -546,7 +527,6 @@ void TestAssets() { // unregister used asset runTest("unregister used asset", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetUnreg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); }); @@ -614,7 +594,6 @@ void TestAssets() { // unregister locked asset runTest("unregister locked asset", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetUnreg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET2_META)); }); @@ -632,7 +611,6 @@ void TestAssets() { currBM += deposit - fee; runTest("unregister asset #1", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetUnreg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET1_META)); }); @@ -645,7 +623,6 @@ void TestAssets() { currBM += deposit - fee; runTest("unregister asset #2", [&] { return owner.m_Wallet->StartTransaction(CreateTransactionParameters(TxType::AssetUnreg) - .SetParameter(TxParameterID::Amount, deposit) .SetParameter(TxParameterID::Fee, fee) .SetParameter(TxParameterID::AssetMetadata, ASSET2_META)); }); @@ -669,7 +646,7 @@ int main () { rules.CA.Enabled = true; rules.CA.LockPeriod = 20; - rules.CA.DepositForList = rules.Coin * 1000; + rules.CA.DepositForList2 = rules.Coin * 1000; rules.MaxRollback = 20; rules.FakePoW = true; rules.pForks[1].m_Height = 5; diff --git a/wallet/unittests/wallet_test.cpp b/wallet/unittests/wallet_test.cpp index ed0e9aefe..5f0f3a0de 100644 --- a/wallet/unittests/wallet_test.cpp +++ b/wallet/unittests/wallet_test.cpp @@ -4326,10 +4326,7 @@ int main() Rules::get().FakePoW = true; Rules::get().pForks[1].m_Height = 100500; // needed for lightning network to work - Rules::get().pForks[2].m_Height = MaxHeight; - Rules::get().pForks[3].m_Height = MaxHeight; - Rules::get().pForks[4].m_Height = MaxHeight; - //Rules::get().DA.MaxAhead_s = 90;// 60 * 1; + Rules::get().DisableForksFrom(2); Rules::get().UpdateChecksum(); wallet::g_AssetsEnabled = true; diff --git a/wasmclient/wasmclient.cpp b/wasmclient/wasmclient.cpp index 7c8d594d9..752bdd6cc 100644 --- a/wasmclient/wasmclient.cpp +++ b/wasmclient/wasmclient.cpp @@ -662,7 +662,7 @@ class WasmWalletClient } std::weak_ptr weak2 = m_Client; - WasmAppApi::ClientThread_Create(m_Client.get(), apiver, appid, appname, false, + WasmAppApi::ClientThread_Create(m_Client.get(), apiver, appid, appname, 0, false, [cb, weak2](WasmAppApi::Ptr wapi) { if (!wapi)