chaincodelabs / libmultiprocess

C++ library and code generator making it easy to call functions and reference objects in different processes

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to define custom parameters in an interface data definition (*.capnp) ?

ariard opened this issue · comments

I've successfully added and built API/data definitions for my new Validation interface

    namespace interfaces {
    
    //! Inteface giving clients access to the validation engine.
    class Validation
    {
    public:
        virtual ~Validation() {}
    
        // Check if headers are valid.
        virtual bool validateHeaders(const BlockHeader& header) = 0;
    };
    
    
    } // namespace interfaces
    using Cxx = import "/capnp/c++.capnp";
    $Cxx.namespace("ipc::capnp::messages");
    
    using Proxy = import "/mp/proxy.capnp";
    $Proxy.include("interfaces/validation.h");
    $Proxy.include("ipc/capnp/validation.capnp.h");
    
    interface Validation $Proxy.wrap("interfaces::Validation") {
        destroy @0 (context :Proxy.Context) -> ();
        validateHeaders @1 (context :Proxy.Context, header: BlockHeader) -> (result: Bool);
    }

I would like to add a custom parameters to my interface :

struct BlockHeader $Proxy.wrap("BlockHeader")
{
    nVersion @0 :Int32;
    hashPrevBlock @1 :Data;
    hashMerkleRoot @2 :Data;
    nTime @3 :UInt32;
    nBits @4 :UInt32;
    nNonce @5 :UInt32;
}

But so far, I'm hitting libmultiprocess compilations errors which are beyond my understanding for
now.

AFAIU by observing the interfaces in #10102, you have two options to add a custom parameters :

  • wrapping a struct duplicated in the API definition (e.g struct WalletTxOut $Proxy.wrap("interfaces::WalletTxOut"))
  • declaring a custom reader/builder in "types files" linking API/data definitions (e.g CustomReadMessage/CustomBuildMessage)

I should rebase my branch on top of #10102, as this branch includes a lot more of common helpers.

Feel free to correct the terminology I used, I'm progressively catching up on libmultiprocess usage :)

I'm happy to help debug if you post a git tag. I think probably for your case, you don't need to build on bitcoin/bitcoin#10102 and just bitcoin/bitcoin#19160 should be sufficient.

Everything you posted and wrote is right. To use custom C++ types in interfaces, you need to either use $Proxy.wrap and list all fields in the type, or you need implement CustomReadField/CustomWriteField/CustomPassField overloads to read/write the C++ type as a capnp type.

The CustomReadMessage/CustomBuildMessage overloads you mentioned are added in bitcoin/bitcoin#10102. They are a simpler alternative to CustomReadField/CustomWriteField/CustomPassField and can be defined in .cpp instead of .h files since they aren't template functions. bitcoin/bitcoin#10102 also adds CustomReadField/CustomWriteField/CustomPassField overload that detect if a type has Serialize/Unserialize methods and will use those if them if they are available.

Thanks to propose to help on the debug, here the git tag : ariard/bitcoin@ddcfd07. Note, you need to pass the following configuration flag --enable-altnet on top of the --enable-multiprocess one.

I'm trying to follow the first path for my custom C++ types, i.e $Proxy.wrap and list all fields in the type. I'm encountering the following build error :

/home/user/Bitcoin/bitcoin/depends/x86_64-pc-linux-gnu/include/mp/proxy-types.h:942:30: error: no matching function for call to ‘BuildPrimitive(mp::InvokeContext&, const uint256&, mp::TypeList<capnp::Data::Builder>)’
     output.set(BuildPrimitive(invoke_context, std::forward<Value>(value), TypeList<decltype(output.get())>()));                                                                                                  
                ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       

AFAICT, such BuildPrimitive() is present in bitcoin/bitcoin#10102 to build the node interface custom types (in src/ipc/capnp/node-types.h). Though it's just returning a ::capnp::Void, I'll try to do the same for my Validation interface.

The BuildPrimitive error indicates that no Build overload is present that can convert const uint256& C++ values to capnp::Data values. (Sorry about the confusing error message. I want to improve these errors by collapsing Build* overloads with C++17 if constexpr expressions in #46. This error happens because BuildPrimitive is the lowest priority build function that gets called when no other build functions can be applied the data type).

Because uint256 is a serializeable type, the fix for this is to supply a CustomBuildField function that can serialize it, like:
https://github.com/ryanofsky/bitcoin/blob/db776ff2e92eb51fd51f56f9557546d4484a44d9/src/ipc/capnp/common-types.h#L248-L262 added in bitcoin/bitcoin#10102

I'm building your branch and can post a patch soon.

Following commit should fix the BuildPrimitive error: ryanofsky/bitcoin@e53c7a9. It just pulls in common-types.h functions from bitcoin/bitcoin#10102 to be able to handle serializable types.

There are still some other build errors on the branch, which I can try to help with, so feel free to ask any followups!

Thanks for the answer on this, I finally fixed the other build errors by rebasing and tweaking few others files. I can build the data definitions I want and making progress on my altnet branch.

I don't have other libmultiprocess questions for now :)

I don't have other libmultiprocess questions for now :)

Will close this issue, but feel free to reopen or post questions or work-in-progress code in new issues. Happy to help!

Sure, fyi the WIP branch is here: https://github.com/ariard/bitcoin/commits/2021-07-altnet-lightning, where I'm able to chain multiple processes : bitcoin-node -> bitcoin-altnet -> altnet-lightning but give me few more days to rebase/cleanup code/test with lightning driver then I think I'll have more advanced questions on the code generator itself!