Clean explorer API and events observer for crypto currencies.
Deploy it in less than 30 seconds!
go get -u github.com/trustwallet/blockatlas
cd blockatlas
// Start API server
go build -o blockatlas . && ./blockatlas api
//Start Observer
go build -o blockatlas . && ./blockatlas observer
Using Docker Hub:
docker run -it -p 8420:8420 trustwallet/blockatlas
Build and run from local Dockerfile:
docker build -t blockatlas .
docker run -p 8420:8420 blockatlas
- Setup Redis
brew install redis // Install Redis using Homebrew
ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents // Enable Redis autostart
- Running in the IDE ( GoLand )
- Run
- Edit configuration
- New Go build configuration
- Select
directory
as configuration type - Set
api
as program argument and-i
as Go tools argument
Block Atlas can run just fine without configuration.
If you want to use custom RPC endpoints, or enable coins without public RPC (like Nimiq),
you can configure Block Atlas over config.yml
or environment variables.
By default, config.yml
is loaded from the working directory.
Example (config.yml
):
nimiq:
api: http://localhost:8648
#...
The rest gets loaded from the environment variables.
Every config option is available under the ATLAS_
prefix.
Example:
ATLAS_NIMIQ_API=http://localhost:8648 \
blockatlas
Swagger API docs provided at path /swagger/index.html
-
After creating a new route, add comments to your API source code, See Declarative Comments Format.
-
Download Swag for Go by using:
$ go get -u github.com/swaggo/swag/cmd/swag
-
Run the Swag in your Go project root folder.
$ swag init
To run the unit tests: make test
All integration tests are generated automatically. You only need to set the environment to your coin in the config file.
The tests use a different build constraint, named integration
.
To run the integration tests: make integration
or you can run manually: TEST_CONFIG=$(TEST_CONFIG) TEST_COINS=$(TEST_COINS) go test -tags=integration -v ./pkg/integration
-
If you need to change the parameters used in our tests, update the file
pkg/integration/testdata/fixtures.json
-
To exclude an API from integration tests, you need to add the route inside the file
pkg/integration/testdata/exclude.json
E.g.:
[
"/v2/ethereum/collections/:owner",
"/v2/ethereum/collections/:owner/collection/:collection_id"
]
Use the package pkg/errors
for create a new error.
An error in Go is any implementing interface with an Error() string method. We overwrite the error object by our error struct:
type Error struct {
Err error
Type Type
meta map[string]interface{}
stack []string
}
To be easier the error construction, the package provides a function named E, which is short and easy to type:
func E(args ...interface{}) *Error
E.g.:
-
just error:
errors.E(err)
-
error with message:
errors.E(err, "new message to append")
-
error with type:
errors.E(err, errors.TypePlatformReques)
-
error with type and message:
errors.E(err, errors.TypePlatformReques, "new message to append")
-
error with type and meta:
errors.E(err, errors.TypePlatformRequest, errors.Params{
"coin": "Ethereum",
"method": "CurrentBlockNumber",
})
- error with meta:
errors.E(err, errors.Params{
"coin": "Ethereum",
"method": "CurrentBlockNumber",
})
- error with type and meta:
errors.E(err, errors.TypePlatformRequest, errors.Params{
"coin": "Ethereum",
"method": "CurrentBlockNumber",
})
- error with type, message and meta:
errors.E(err, errors.TypePlatformRequest, "new message to append", errors.Params{
"coin": "Ethereum",
"method": "CurrentBlockNumber",
})
- You can send the errors to sentry using
.PushToSentry()
errors.E(err, errors.TypePlatformReques).PushToSentry()
All fatal errors emitted by logger package already send the error to Sentry
const (
TypeNone Type = iota
TypePlatformUnmarshal
TypePlatformNormalize
TypePlatformUnknown
TypePlatformRequest
TypePlatformClient
TypePlatformError
TypePlatformApi
TypeLoadConfig
TypeLoadCoins
TypeObserver
TypeStorage
TypeAssets
TypeUtil
TypeCmd
TypeUnknown
)
Use the package pkg/logger
for logs.
E.g.:
-
Log message:
logger.Info("Loading Observer API")
-
Log message with params:
logger.Info("Running application", logger.Params{"bind": bind})
-
Fatal with error:
logger.Fatal("Application failed", err)
-
The method parameters don't have a sort. You just need to pass them to the method:
logger.Fatal(err, "Application failed")
-
Create a simple error log:
logger.Error(err)
-
Create an error log with a message:
logger.Error("Failed to initialize API", err)
-
Create an error log, with error, message, and params:
p := logger.Params{
"platform": handle,
"coin": platform.Coin(),
}
err := platform.Init()
if err != nil {
logger.Error("Failed to initialize API", err, p)
}
-
Debug log:
logger.Debug("Loading Observer API")
orlogger.Debug("Loading Observer API", logger.Params{"bind": bind})
-
Warning log:
logger.Warn("Warning", err)
orlogger.Warn(err, "Warning")
orlogger.Warn("Warning", err, logger.Params{"bind": bind})
The Blockatlas can collect and expose by expvar's
, metrics about the application healthy and clients and server requests.
Prometheus or another service can collect metrics provided from the /metrics
endpoint.
To protect the route, you can set the environment variables METRICS_API_TOKEN
, and this route starts to require the auth bearer token.
If you'd like to add support for a new blockchain, feel free to file a pull request. Note that most tokens that run on top of other chains are already supported and don't require code changes (e.g. ERC-20).
The best way to submit feedback and report bugs is to open a GitHub issue. Please be sure to include your operating system, version number, and steps to reproduce reported bugs.