EOSIO / eosio.cdt

EOSIO.CDT (Contract Development Toolkit) is a suite of tools used to build EOSIO contracts
http://eosio.github.io/eosio.cdt
MIT License
511 stars 288 forks source link

I receive fatal error: 'arpa/inet.h' when I want to link an external http library #1234

Closed nidhaloff closed 2 years ago

nidhaloff commented 2 years ago

I want to use this header-only library to make http requests. I used the lib many times and I had no issues. However, I think there is compatibility issues with eosio.cdt, but I'm not sure therefore I'm asking here.

I'm using eosio-cpp to compile the contract. It is working perfectly. I don't know how to link external libraries therefore, I prefer to use header-only libraries in my project. Basically, I copy paste the header files under include/ and then build the contract with eosio-cpp. I used nlohmann::json in the past and I could build the contract with eosio-cpp. Now I want to do the same thing by adding cpp-httplib, but I'm getting the error

httplib.h:162:10: fatal error: 'arpa/inet.h'
#include <arpa/inet.h>

I used this library in many projects and never got this error, so is it a compatibility issue with eosio.cdt? If yes can you please suggest an alternative? and how to build/include external libraries in my smart contract project? I could not find any resources on this topic.

praphael commented 2 years ago

You will not be able to make an HTTP request directly from within a smart contract.

Producing data and consuming data from the outside world on the blockchain is normally done through oracles. You might want to take a look at Provable, LiquidOracles

Another option would be to monitor the chain through the state_history_plugin, use fill-queue or fill-pg(aka history-tools), filter based on contract type, then act accordingly.

nidhaloff commented 2 years ago

@praphael Thanks for the answer, but why isn't it possible though?

Is this specific to http or do you mean that it is generally prohibited to connect to the outside world from the smart contract?

praphael commented 2 years ago

Nondeterministic behavior is not allowed, because the blockchain has to be able to validate smart contract execution.

nidhaloff commented 2 years ago

@praphael But why is sending http requests nondeterministic? can you please explain?

My goal is to send http requests without updating state (so just notify), so how can this be a nondeterministic behavior?

nidhaloff commented 2 years ago

@heifner Can you please explain why this is not possible before closing the issue?

heifner commented 2 years ago

http is not deterministic. The endpoint might not be available when validation nodes are attempting to validate the contract execution.

praphael commented 2 years ago

@praphael But why is sending http requests nondeterministic? can you please explain?

My goal is to notify an external server whenever I update my multi_index table or after transaction validation, so how can this be a nondeterministic behavior?

Because the server could have one response at a certain time, and then when another node tries to replay the transaction, the server could responds with something different. Or not even exist at all. This is major problem with a blockchain as two or more nodes may not be able to reach a consensus on the results of the execution of the smart contract.

Please see https://developers.eos.io/welcome/latest/protocol-guides/consensus_protocol

This discussion is probably better suited for Stackexchange https://eosio.stackexchange.com/

nidhaloff commented 2 years ago

@praphael @heifner thanks for the explanation. So how can I listen on table changes?

I know that I can read the multi_index table using eosjs, but is there any publish/subscribe approach, where I can just connect to the network and receive changes whenever something happens on the chain?

This must be possible because some EOSIO websites show how the mainnet is being updated in real time

heifner commented 2 years ago

I would look at something like: https://dfuse.eosnation.io/

nidhaloff commented 2 years ago

@heifner thanks, however, dfuse.eosnation.io is an external service provider and I need to get an api key to use their services.

Why can't I do this alone without any external services or how did they implement this? that's what I'm actually interested in.

heifner commented 2 years ago

You can do this yourself using state_history_plugin (push) or trace_api_plugin (pull) but it will take some work to create a client. https://developers.eos.io/welcome/latest/tools/history-tools/index

heifner commented 2 years ago

I would recommend you ask for advice on telegram https://t.me/joinchat/0uhWYfXVpPlkNTA1

praphael commented 2 years ago

@nidhaloff If it was not clear from Kevin's post, in order to do this yourself you would have to be running your own nodeos instance, connecting P2P to the chain of interest. For some chains such as mainnet this will most likely require a dedicated machine/instance of moderate capability. You can then experiment with the different plugins ( trace_history, state_history), and then write a a client in any language you want, e.g Python, which acts appropriately on the information.

nidhaloff commented 2 years ago

@praphael Thank you. That's exactly what I'm doing now I'm running a private chain (a private nodeos instance in a VM) and I'm working on a proof of concept. So can I write an extra plugin that will expose a web socket or an mqtt pub-sub interface? Is there any example for this?

praphael commented 2 years ago

If you are referring to a nodeos plugin, that would be unnecessary and time consuming.
From your use case (private_chain) it sounds like the simplest and fastest way is to use the trace_api_plugin, as it uses standard HTTP requests. It is a pull API however and so doesn't have filtering, etc. so you would have to inspect every block https://developers.eos.io/manuals/eos/latest/nodeos/plugins/trace_api_plugin/index

You can also use the state_history_plugin, which is a push API. https://developers.eos.io/manuals/eos/latest/nodeos/plugins/state_history_plugin/index This would be more suitable for chains which can get busy such as mainnet and WAX .
The two endpoints we have for state_history are currently fill-pg (fills up PostgreSQL db) https://github.com/eosio/history-tools and fill-queue ( pushes to MQ protocol, e.g RabbitMQ). https://github.com/EOSIO/fill-queue. In theory you could also write your own state_history endpoint, but probably unnecessary.