2020-10-13 10:29:42 +00:00
Tutorial: Build a personalized daemon
=====================================
For the following tutorial, we will make references to https://github.com/Giulio2002/hello-tg-daemon.
2021-05-26 10:35:39 +00:00
We are going to build our daemon using golang and Erigon packages, so first of all we are going to create a file in which we are going to store our API methods and informations. (`api.go` ).
2020-10-13 10:29:42 +00:00
our daemon will only contain one method: `myNamespace_getBlockNumberByHash` which will return the block number associated to certain hash.
.. code-block :: go
package main
import (
"context"
2021-08-16 03:12:15 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
2021-05-26 10:35:39 +00:00
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/core/rawdb"
2020-10-13 10:29:42 +00:00
)
type API struct {
2021-08-16 03:12:15 +00:00
db kv.RoDB
2020-10-13 10:29:42 +00:00
}
type ExampleAPI interface {
GetBlockNumberByHash(ctx context.Context, hash common.Hash) (uint64, error)
}
2021-08-16 03:12:15 +00:00
func NewAPI(db kv.RoDB) *API {
return &API{db}
2020-10-13 10:29:42 +00:00
}
func (api *API) GetBlockNumberByHash(ctx context.Context, hash common.Hash) (uint64, error) {
2021-08-16 03:12:15 +00:00
tx, err := api.db.BeginRo(ctx)
if err != nil {
return 0, err
}
defer tx.Rollback()
block, err := rawdb.ReadBlockByHash(tx, hash)
if err != nil {
return 0, err
}
return block.NumberU64(), nil
2020-10-13 10:29:42 +00:00
}
2021-08-16 03:12:15 +00:00
The type `Api` is the type that is going to contain the methods for our custom daemon. This type has one member: `db` object used to interact with the Erigon node remotely. Member `db` behave like normal db object and can be used alongside with the rawdb package.
2020-10-13 10:29:42 +00:00
In our example we are making an rpcdaemon call that by receiving a certain block hash, it give the block number associated as an output. this is all done in `GetBlockNumberByHash` .
Now we are going to make our `main.go` where we are going to serve the api we made in `api.go` .
.. code-block :: go
package main
import (
"os"
2021-08-16 03:12:15 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
2021-05-26 10:35:39 +00:00
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli"
"github.com/ledgerwatch/erigon/cmd/utils"
"github.com/ledgerwatch/erigon/rpc"
2021-08-16 03:12:15 +00:00
"github.com/ledgerwatch/log/v3"
2020-10-13 10:29:42 +00:00
"github.com/spf13/cobra"
)
func main() {
cmd, cfg := cli.RootCommand()
2021-08-16 03:12:15 +00:00
rootCtx, rootCancel := utils.RootContext()
2020-10-13 10:29:42 +00:00
cmd.RunE = func(cmd *cobra.Command, args []string) error {
2021-08-16 03:12:15 +00:00
logger := log.New()
db, _, _, _, err := cli.RemoteServices(*cfg, logger, rootCancel)
2020-10-13 10:29:42 +00:00
if err != nil {
2021-08-16 03:12:15 +00:00
log.Error("Could not connect to DB", "error", err)
2020-10-13 10:29:42 +00:00
return nil
}
2021-08-16 03:12:15 +00:00
defer db.Close()
2020-10-13 10:29:42 +00:00
2021-08-16 03:12:15 +00:00
if err := cli.StartRpcServer(cmd.Context(), *cfg, APIList(db)); err != nil {
log.Error(err.Error())
return nil
}
return nil
2020-10-13 10:29:42 +00:00
}
2021-08-16 03:12:15 +00:00
if err := cmd.ExecuteContext(rootCtx); err != nil {
2020-10-13 10:29:42 +00:00
log.Error(err.Error())
os.Exit(1)
}
}
2021-08-16 03:12:15 +00:00
func APIList(db kv.RoDB) []rpc.API {
api := NewAPI(db)
2020-10-13 10:29:42 +00:00
customAPIList := []rpc.API{
{
Namespace: "myNamespace",
Public: true,
Service: ExampleAPI(api),
Version: "1.0",
},
}
2021-08-16 03:12:15 +00:00
return customAPIList
2020-10-13 10:29:42 +00:00
}
2021-08-16 03:12:15 +00:00
In the main we are just running our rpcdaemon as we defined it in `APIList` , in fact in `APIList` we are configuring our custom rpcdaemon to serve the ExampleAPI's methods on namespace `myNamespace` meaning that in order to call GetBlockNumberByHash via json rpc we have to call method `myNamespace_getBlockNumberByHash` .
2020-10-13 10:29:42 +00:00
Let's now try it:
.. code-block :: sh
$ go build
2021-08-16 03:12:15 +00:00
$ ./hello-erigon-daemon --http.api=myNamespace # the flag enables our namespace.
2020-10-13 10:29:42 +00:00
2021-08-16 03:12:15 +00:00
**Note: Remember to run it with --private.api.addr=localhost:9090 and/or --datadir <path-to-erigon-data>**
2020-10-13 10:29:42 +00:00
now it should be all set and we can test it with:
.. code-block :: sh
2020-10-13 12:18:33 +00:00
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"myNamespace_getBlockNumberByHash","params":["ANYHASH"],"id":1}' localhost:8545
2020-10-13 10:29:42 +00:00
another example of custom daemon can be found at https://github.com/torquem-ch/project-1/blob/master/api.go.
2021-08-16 03:12:15 +00:00
Happy Building ~~~.