Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07df0337d1 | ||
|
|
551efea107 | ||
|
|
ebaacb3733 | ||
|
|
a295e7d4b2 |
@@ -14,7 +14,7 @@ on:
|
||||
env:
|
||||
# Needed until we can incorporate docker startup into the executor container
|
||||
DOCKER_HOST: unix:///var/run/dind.sock
|
||||
SO_VERSION: v1.1.0-b7f215d-202401282321 # contains fixes for plugeth stack
|
||||
SO_VERSION: v1.1.0-e0b5318-202309201927 # contains fixes for plugeth stack
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
+5
-2
@@ -1,9 +1,9 @@
|
||||
FROM golang:1.19-alpine as debugger
|
||||
FROM golang:1.21-alpine as debugger
|
||||
|
||||
# Include dlv
|
||||
RUN go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
|
||||
FROM golang:1.19-alpine as builder
|
||||
FROM golang:1.21-alpine as builder
|
||||
|
||||
RUN apk --update --no-cache add gcc musl-dev binutils-gold git
|
||||
|
||||
@@ -28,6 +28,8 @@ RUN GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -
|
||||
# app container
|
||||
FROM alpine
|
||||
|
||||
RUN apk --update --no-cache add bash jq curl
|
||||
|
||||
ARG USER="vdm"
|
||||
ARG CONFIG_FILE="./environments/example.toml"
|
||||
|
||||
@@ -41,6 +43,7 @@ USER $USER
|
||||
COPY --chown=5000:5000 --from=builder /go/src/github.com/cerc-io/ipld-eth-server/$CONFIG_FILE config.toml
|
||||
COPY --chown=5000:5000 --from=builder /go/src/github.com/cerc-io/ipld-eth-server/entrypoint.sh .
|
||||
|
||||
RUN mkdir -p nitro-data && chown -R 5000:5000 nitro-data
|
||||
|
||||
# keep binaries immutable
|
||||
COPY --from=builder /go/src/github.com/cerc-io/ipld-eth-server/ipld-eth-server ipld-eth-server
|
||||
|
||||
@@ -35,3 +35,49 @@ func addDatabaseFlags(command *cobra.Command) {
|
||||
viper.BindPFlag("database.user", command.PersistentFlags().Lookup("database-user"))
|
||||
viper.BindPFlag("database.password", command.PersistentFlags().Lookup("database-password"))
|
||||
}
|
||||
|
||||
func addNitroFlags(command *cobra.Command) {
|
||||
// nitro flags
|
||||
command.PersistentFlags().Bool("nitro-run-node-in-process", false, "nitro run node in process")
|
||||
command.PersistentFlags().String("nitro-rpc-query-rates-file", "", "nitro rpcQueryRatesFile")
|
||||
|
||||
command.PersistentFlags().String("nitro-pk", "", "nitro pk")
|
||||
command.PersistentFlags().String("nitro-chain-pk", "", "nitro chainPk")
|
||||
command.PersistentFlags().String("nitro-chain-url", "ws://127.0.0.1:8545", "nitro chainUrl")
|
||||
command.PersistentFlags().String("nitro-na-address", "", "nitro naAddress")
|
||||
command.PersistentFlags().String("nitro-vpa-address", "", "nitro vpaAddress")
|
||||
command.PersistentFlags().String("nitro-ca-address", "", "nitro caAddress")
|
||||
command.PersistentFlags().Bool("nitro-use-durable-store", false, "nitro useDurableStore")
|
||||
command.PersistentFlags().String("nitro-durable-store-folder", "", "nitro durableStoreFolder")
|
||||
command.PersistentFlags().Int("nitro-msg-port", 3005, "nitro msgPort")
|
||||
command.PersistentFlags().Int("nitro-rpc-port", 4005, "nitro rpcPort")
|
||||
command.PersistentFlags().Int("nitro-ws-msg-port", 5005, "nitro wsMsgPort")
|
||||
command.PersistentFlags().Uint("nitro-chain-start-block", 0, "nitro chainStartBlock")
|
||||
command.PersistentFlags().String("nitro-tls-cert-filepath", "", "nitro tlsCertFilepath")
|
||||
command.PersistentFlags().String("nitro-tls-key-filepath", "", "nitro tlsKeyFilepath")
|
||||
|
||||
command.PersistentFlags().String("nitro-endpoint", "", "nitro endpoint")
|
||||
command.PersistentFlags().Bool("nitro-is-secure", false, "nitro isSecure")
|
||||
|
||||
// nitro flag bindings
|
||||
viper.BindPFlag("nitro.runNodeInProcess", command.PersistentFlags().Lookup("nitro-run-node-in-process"))
|
||||
viper.BindPFlag("nitro.rpcQueryRatesFile", command.PersistentFlags().Lookup("nitro-rpc-query-rates-file"))
|
||||
|
||||
viper.BindPFlag("nitro.inProcesssNode.pk", command.PersistentFlags().Lookup("nitro-pk"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.chainPk", command.PersistentFlags().Lookup("nitro-chain-pk"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.chainUrl", command.PersistentFlags().Lookup("nitro-chain-url"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.naAddress", command.PersistentFlags().Lookup("nitro-na-address"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.vpaAddress", command.PersistentFlags().Lookup("nitro-vpa-address"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.caAddress", command.PersistentFlags().Lookup("nitro-ca-address"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.useDurableStore", command.PersistentFlags().Lookup("nitro-use-durable-store"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.durableStoreFolder", command.PersistentFlags().Lookup("nitro-durable-store"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.msgPort", command.PersistentFlags().Lookup("nitro-msg-port"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.rpcPort", command.PersistentFlags().Lookup("nitro-rpc-port"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.wsMsgPort", command.PersistentFlags().Lookup("nitro-ws-msg-port"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.chainStartBlock", command.PersistentFlags().Lookup("nitro-chain-start-block"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.tlsCertFilepath", command.PersistentFlags().Lookup("nitro-tls-cert-filepath"))
|
||||
viper.BindPFlag("nitro.inProcesssNode.tlsKeyFilepath", command.PersistentFlags().Lookup("nitro-tls-key-filepath"))
|
||||
|
||||
viper.BindPFlag("nitro.remoteNode.nitroEndpoint", command.PersistentFlags().Lookup("nitro-endpoint"))
|
||||
viper.BindPFlag("nitro.remoteNode.isSecure", command.PersistentFlags().Lookup("nitro-is-secure"))
|
||||
}
|
||||
|
||||
+212
-4
@@ -16,7 +16,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -26,15 +31,26 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v5/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/mailgun/groupcache/v2"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/statechannels/go-nitro/node/engine"
|
||||
"github.com/statechannels/go-nitro/node/engine/chainservice"
|
||||
nitroStore "github.com/statechannels/go-nitro/node/engine/store"
|
||||
"github.com/statechannels/go-nitro/paymentsmanager"
|
||||
"github.com/statechannels/go-nitro/rpc/transport"
|
||||
"golang.org/x/exp/slog"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v5/pkg/graphql"
|
||||
srpc "github.com/cerc-io/ipld-eth-server/v5/pkg/rpc"
|
||||
s "github.com/cerc-io/ipld-eth-server/v5/pkg/serve"
|
||||
v "github.com/cerc-io/ipld-eth-server/v5/version"
|
||||
nitroNode "github.com/statechannels/go-nitro/node"
|
||||
nitrop2pms "github.com/statechannels/go-nitro/node/engine/messageservice/p2p-message-service"
|
||||
nitroRpc "github.com/statechannels/go-nitro/rpc"
|
||||
nitroHttpTransport "github.com/statechannels/go-nitro/rpc/transport/http"
|
||||
)
|
||||
|
||||
var ErrNoRpcEndpoints = errors.New("no rpc endpoints is available")
|
||||
@@ -55,6 +71,8 @@ func serve() {
|
||||
logWithCommand.Infof("ipld-eth-server version: %s", v.VersionWithMeta)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
defer wg.Wait()
|
||||
|
||||
serverConfig, err := s.NewConfig()
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
@@ -75,7 +93,41 @@ func serve() {
|
||||
}
|
||||
|
||||
server.Serve(wg)
|
||||
if err := startServers(server, serverConfig); err != nil {
|
||||
|
||||
var voucherValidator paymentsmanager.VoucherValidator
|
||||
|
||||
nitroConfig := serverConfig.Nitro
|
||||
if nitroConfig.RunNodeInProcess {
|
||||
log.Info("Running an in-process Nitro node")
|
||||
|
||||
pm, nitroRpcServer := initNitroInProcess(wg, nitroConfig)
|
||||
defer pm.Stop()
|
||||
defer nitroRpcServer.Close()
|
||||
|
||||
voucherValidator = paymentsmanager.InProcessVoucherValidator{PaymentsManager: *pm}
|
||||
} else {
|
||||
log.Info("Connecting to a remote Nitro node")
|
||||
|
||||
isSecure := nitroConfig.RemoteNode.IsSecure
|
||||
nitroRpcClient, err := nitroRpc.NewHttpRpcClient(nitroConfig.RemoteNode.NitroEndpoint, isSecure)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
defer nitroRpcClient.Close()
|
||||
|
||||
voucherValidator = nitroRpc.RemoteVoucherValidator{Client: nitroRpcClient}
|
||||
}
|
||||
|
||||
queryRates, err := readRpcQueryRates(nitroConfig.RpcQueryRatesFile)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
|
||||
paymentMiddleware := func(next http.Handler) http.Handler {
|
||||
return paymentsmanager.HTTPMiddleware(next, voucherValidator, queryRates)
|
||||
}
|
||||
|
||||
if err := startServers(server, serverConfig, [](func(next http.Handler) http.Handler){paymentMiddleware}); err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
graphQL, err := startEthGraphQL(server, serverConfig)
|
||||
@@ -102,10 +154,9 @@ func serve() {
|
||||
graphQL.Stop()
|
||||
}
|
||||
server.Stop()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func startServers(server s.Server, settings *s.Config) error {
|
||||
func startServers(server s.Server, settings *s.Config, httpMiddlewares [](func(next http.Handler) http.Handler)) error {
|
||||
if settings.IPCEnabled {
|
||||
logWithCommand.Debug("starting up IPC server")
|
||||
_, _, err := srpc.StartIPCEndpoint(settings.IPCEndpoint, server.APIs())
|
||||
@@ -128,7 +179,7 @@ func startServers(server s.Server, settings *s.Config) error {
|
||||
|
||||
if settings.HTTPEnabled {
|
||||
logWithCommand.Debug("starting up HTTP server")
|
||||
_, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"vdb", "eth", "debug", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||
_, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"vdb", "eth", "debug", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{}, httpMiddlewares)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -260,6 +311,8 @@ func init() {
|
||||
|
||||
addDatabaseFlags(serveCmd)
|
||||
|
||||
addNitroFlags(serveCmd)
|
||||
|
||||
// flags for all config variables
|
||||
// eth graphql and json-rpc parameters
|
||||
serveCmd.PersistentFlags().Bool("server-graphql", false, "turn on the eth graphql server")
|
||||
@@ -339,3 +392,158 @@ func init() {
|
||||
viper.BindPFlag("validator.enabled", serveCmd.PersistentFlags().Lookup("validator-enabled"))
|
||||
viper.BindPFlag("validator.everyNthBlock", serveCmd.PersistentFlags().Lookup("validator-every-nth-block"))
|
||||
}
|
||||
|
||||
// Initializes an in-process Nitro node, payments manager and a Nitro RPC server
|
||||
func initNitroInProcess(wg *sync.WaitGroup, nitroConfig *s.NitroConfig) (*paymentsmanager.PaymentsManager, *nitroRpc.RpcServer) {
|
||||
nitroNode, err := initNitroNode(&nitroConfig.InProcessNode)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
|
||||
pm, err := paymentsmanager.NewPaymentsManager(nitroNode)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
pm.Start(wg)
|
||||
|
||||
tlsCertFilepath := nitroConfig.InProcessNode.TlsCertFilepath
|
||||
tlsKeyFilepath := nitroConfig.InProcessNode.TlsKeyFilepath
|
||||
|
||||
var cert *tls.Certificate
|
||||
if tlsCertFilepath != "" && tlsKeyFilepath != "" {
|
||||
*cert, err = tls.LoadX509KeyPair(tlsCertFilepath, tlsKeyFilepath)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
nitroRpcServer, err := initNitroRpcServer(nitroNode, pm, cert, nitroConfig.InProcessNode.RpcPort)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
|
||||
return &pm, nitroRpcServer
|
||||
}
|
||||
|
||||
// https://github.com/cerc-io/go-nitro/blob/release-v0.1.1-ts-port-0.1.7/internal/node/node.go#L17
|
||||
func initNitroNode(config *s.InProcessNitroNodeConfig) (*nitroNode.Node, error) {
|
||||
pkString := config.Pk
|
||||
useDurableStore := config.UseDurableStore
|
||||
durableStoreFolder := config.DurableStoreFolder
|
||||
msgPort := config.MsgPort
|
||||
wsMsgPort := config.WsMsgPort
|
||||
chainUrl := config.ChainUrl
|
||||
chainStartBlock := config.ChainStartBlock
|
||||
chainPk := config.ChainPk
|
||||
naAddress := config.NaAddress
|
||||
vpaAddress := config.VpaAddress
|
||||
caAddress := config.CaAddress
|
||||
|
||||
chainAuthToken := ""
|
||||
publicIp := "0.0.0.0"
|
||||
|
||||
chainOpts := chainservice.ChainOpts{
|
||||
ChainUrl: chainUrl,
|
||||
ChainStartBlock: chainStartBlock,
|
||||
ChainAuthToken: chainAuthToken,
|
||||
ChainPk: chainPk,
|
||||
NaAddress: common.HexToAddress(naAddress),
|
||||
VpaAddress: common.HexToAddress(vpaAddress),
|
||||
CaAddress: common.HexToAddress(caAddress),
|
||||
}
|
||||
|
||||
storeOpts := nitroStore.StoreOpts{
|
||||
PkBytes: common.Hex2Bytes(pkString),
|
||||
UseDurableStore: useDurableStore,
|
||||
DurableStoreFolder: durableStoreFolder,
|
||||
}
|
||||
|
||||
bootPeers := []string{}
|
||||
messageOpts := nitrop2pms.MessageOpts{
|
||||
PkBytes: common.Hex2Bytes(pkString),
|
||||
TcpPort: msgPort,
|
||||
WsMsgPort: wsMsgPort,
|
||||
BootPeers: bootPeers,
|
||||
PublicIp: publicIp,
|
||||
}
|
||||
|
||||
ourStore, err := nitroStore.NewStore(storeOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info("Initializing message service...", " tcp port=", msgPort, " web socket port=", wsMsgPort)
|
||||
messageService := nitrop2pms.NewMessageService(messageOpts)
|
||||
|
||||
// Compare chainOpts.ChainStartBlock to lastBlockNum seen in store. The larger of the two
|
||||
// gets passed as an argument when creating NewEthChainService
|
||||
storeBlockNum, err := ourStore.GetLastBlockNumSeen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if storeBlockNum > chainOpts.ChainStartBlock {
|
||||
chainOpts.ChainStartBlock = storeBlockNum
|
||||
}
|
||||
|
||||
log.Info("Initializing chain service...")
|
||||
ourChain, err := chainservice.NewEthChainService(chainOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node := nitroNode.New(
|
||||
messageService,
|
||||
ourChain,
|
||||
ourStore,
|
||||
&engine.PermissivePolicy{},
|
||||
)
|
||||
|
||||
return &node, nil
|
||||
}
|
||||
|
||||
func initNitroRpcServer(node *nitroNode.Node, pm paymentsmanager.PaymentsManager, cert *tls.Certificate, rpcPort int) (*nitroRpc.RpcServer, error) {
|
||||
var transport transport.Responder
|
||||
var err error
|
||||
|
||||
slog.Info("Initializing Nitro HTTP RPC transport...")
|
||||
transport, err = nitroHttpTransport.NewHttpTransportAsServer(fmt.Sprint(rpcPort), cert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcServer, err := nitroRpc.NewRpcServer(node, pm, transport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slog.Info("Completed Nitro RPC server initialization")
|
||||
return rpcServer, nil
|
||||
}
|
||||
|
||||
func readRpcQueryRates(filepath string) (map[string]*big.Int, error) {
|
||||
result := make(map[string]*big.Int)
|
||||
|
||||
if filepath == "" {
|
||||
logWithCommand.Warn("RPC query rates file path not provided")
|
||||
return result, nil
|
||||
}
|
||||
|
||||
jsonFile, err := os.Open(filepath)
|
||||
defer jsonFile.Close()
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
logWithCommand.Warn("RPC query rates file does not exist")
|
||||
return result, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(jsonFile)
|
||||
err = decoder.Decode(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -31,3 +31,27 @@
|
||||
clientName = "Geth" # $ETH_CLIENT_NAME
|
||||
genesisBlock = "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" # $ETH_GENESIS_BLOCK
|
||||
networkID = "1" # $ETH_NETWORK_ID
|
||||
|
||||
[nitro]
|
||||
runNodeInProcess = false # NITRO_RUN_NODE_IN_PROCESS
|
||||
rpcQueryRatesFile = "environments/rpcQueryRates.json" # NITRO_RPC_QUERY_RATES_FILE
|
||||
|
||||
[nitro.inProcesssNode]
|
||||
pk = "" # NITRO_PK
|
||||
chainPk = "" # NITRO_CHAIN_PK
|
||||
chainUrl = "ws://127.0.0.1:8545" # NITRO_CHAIN_URL
|
||||
naAddress = "" # NITRO_NA_ADDRESS
|
||||
vpaAddress = "" # NITRO_VPA_ADDRESS
|
||||
caAddress = "" # NITRO_CA_ADDRESS
|
||||
useDurableStore = true # NITRO_USE_DURABLE_STORE
|
||||
durableStoreFolder = "./data/nitronode" # NITRO_DURABLE_STORE_FOLDER
|
||||
msgPort = 3005 # NITRO_MSG_PORT
|
||||
rpcPort = 4005 # NITRO_RPC_PORT
|
||||
wsMsgPort = 5005 # NITRO_WS_MSG_PORT
|
||||
chainStartBlock = 0 # NITRO_CHAIN_START_BLOCK
|
||||
tlsCertFilepath = "" # NITRO_TLS_CERT_FILEPATH
|
||||
tlsKeyFilepath = "" # NITRO_TLS_KEY_FILEPATH
|
||||
|
||||
[nitro.remoteNode]
|
||||
nitroEndpoint = "127.0.0.1:4005/api/v1" # NITRO_ENDPOINT
|
||||
isSecure = false # NITRO_IS_SECURE
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"eth_getBlockByNumber": 50,
|
||||
"eth_getBlockByHash": 50,
|
||||
"eth_getStorageAt": 50,
|
||||
"eth_getLogs": 50
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/cerc-io/ipld-eth-server/v5
|
||||
|
||||
go 1.19
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/cerc-io/eth-ipfs-state-validator/v5 v5.0.0-alpha
|
||||
@@ -8,7 +8,7 @@ require (
|
||||
github.com/cerc-io/ipfs-ethdb/v5 v5.0.0-alpha
|
||||
github.com/cerc-io/ipld-eth-statedb v0.0.5-alpha
|
||||
github.com/cerc-io/plugeth-statediff v0.1.1
|
||||
github.com/ethereum/go-ethereum v1.11.6
|
||||
github.com/ethereum/go-ethereum v1.12.0 // TODO: Investigate
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/graph-gophers/graphql-go v1.3.0
|
||||
github.com/ipfs/go-cid v0.4.1
|
||||
@@ -17,12 +17,14 @@ require (
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/machinebox/graphql v0.2.2
|
||||
github.com/mailgun/groupcache/v2 v2.3.0
|
||||
github.com/onsi/ginkgo/v2 v2.9.2
|
||||
github.com/onsi/gomega v1.27.4
|
||||
github.com/onsi/ginkgo/v2 v2.11.0
|
||||
github.com/onsi/gomega v1.27.8
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/viper v1.11.0
|
||||
github.com/statechannels/go-nitro v0.1.2
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
||||
gorm.io/driver/postgres v1.3.7
|
||||
gorm.io/gorm v1.23.5
|
||||
)
|
||||
@@ -30,22 +32,22 @@ require (
|
||||
require (
|
||||
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/Jorropo/jsync v1.0.1 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cockroachdb/errors v1.10.0 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20230720154706-692f3b61a3c4 // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230613231145-182959a1fad6 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||
@@ -56,19 +58,19 @@ require (
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
|
||||
github.com/fjl/memsize v0.0.1 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/georgysavva/scany v0.2.9 // indirect
|
||||
github.com/getsentry/sentry-go v0.22.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
@@ -77,19 +79,20 @@ require (
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.12 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.3 // indirect
|
||||
@@ -100,52 +103,32 @@ require (
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||
github.com/ipfs/go-bitfield v1.0.0 // indirect
|
||||
github.com/ipfs/go-bitswap v0.11.0 // indirect
|
||||
github.com/ipfs/go-block-format v0.0.3 // indirect
|
||||
github.com/ipfs/go-blockservice v0.5.0 // indirect
|
||||
github.com/ipfs/boxo v0.13.1 // indirect
|
||||
github.com/ipfs/go-bitfield v1.1.0 // indirect
|
||||
github.com/ipfs/go-block-format v0.1.2 // indirect
|
||||
github.com/ipfs/go-cidutil v0.1.0 // indirect
|
||||
github.com/ipfs/go-datastore v0.6.0 // indirect
|
||||
github.com/ipfs/go-delegated-routing v0.7.0 // indirect
|
||||
github.com/ipfs/go-ds-measure v0.2.0 // indirect
|
||||
github.com/ipfs/go-fetcher v1.6.1 // indirect
|
||||
github.com/ipfs/go-filestore v1.2.0 // indirect
|
||||
github.com/ipfs/go-fs-lock v0.0.7 // indirect
|
||||
github.com/ipfs/go-graphsync v0.14.1 // indirect
|
||||
github.com/ipfs/go-ipfs-blockstore v1.2.0 // indirect
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect
|
||||
github.com/ipfs/go-graphsync v0.15.1 // indirect
|
||||
github.com/ipfs/go-ipfs-blockstore v1.3.0 // indirect
|
||||
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
|
||||
github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect
|
||||
github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect
|
||||
github.com/ipfs/go-ipfs-keystore v0.1.0 // indirect
|
||||
github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect
|
||||
github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipfs-provider v0.8.1 // indirect
|
||||
github.com/ipfs/go-ipfs-routing v0.3.0 // indirect
|
||||
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
|
||||
github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect
|
||||
github.com/ipfs/go-ipfs-util v0.0.3 // indirect
|
||||
github.com/ipfs/go-ipld-cbor v0.0.6 // indirect
|
||||
github.com/ipfs/go-ipld-format v0.4.0 // indirect
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
|
||||
github.com/ipfs/go-ipns v0.3.0 // indirect
|
||||
github.com/ipfs/go-libipfs v0.2.0 // indirect
|
||||
github.com/ipfs/go-ipld-format v0.5.0 // indirect
|
||||
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/ipfs/go-merkledag v0.9.0 // indirect
|
||||
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
|
||||
github.com/ipfs/go-mfs v0.2.1 // indirect
|
||||
github.com/ipfs/go-namesys v0.6.0 // indirect
|
||||
github.com/ipfs/go-path v0.3.0 // indirect
|
||||
github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
|
||||
github.com/ipfs/go-unixfs v0.4.2 // indirect
|
||||
github.com/ipfs/go-unixfsnode v1.5.1 // indirect
|
||||
github.com/ipfs/go-verifcid v0.0.2 // indirect
|
||||
github.com/ipfs/interface-go-ipfs-core v0.8.2 // indirect
|
||||
github.com/ipfs/kubo v0.18.1 // indirect
|
||||
github.com/ipld/edelweiss v0.2.0 // indirect
|
||||
github.com/ipld/go-codec-dagpb v1.5.0 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.19.0 // indirect
|
||||
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
|
||||
github.com/ipfs/go-unixfsnode v1.8.1 // indirect
|
||||
github.com/ipfs/kubo v0.23.0 // indirect
|
||||
github.com/ipld/go-car/v2 v2.10.2-0.20230622090957-499d0c909d33 // indirect
|
||||
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.21.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.14.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
@@ -162,44 +145,37 @@ require (
|
||||
github.com/jinzhu/now v1.1.4 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/koron/go-ssdp v0.0.3 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-doh-resolver v0.4.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p v0.24.2 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.20.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub v0.8.3 // indirect
|
||||
github.com/libp2p/go-libp2p v0.31.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.24.4 // indirect
|
||||
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub v0.9.3 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
|
||||
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.6.0 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.7.3 // indirect
|
||||
github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
|
||||
github.com/libp2p/go-mplex v0.7.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.2.0 // indirect
|
||||
github.com/libp2p/go-nat v0.1.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.3.0 // indirect
|
||||
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/libp2p/go-openssl v0.1.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.4.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.31.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/marten-seemann/webtransport-go v0.4.3 // indirect
|
||||
github.com/matryer/is v1.4.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/miekg/dns v1.1.55 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
@@ -209,29 +185,34 @@ require (
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.8.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.11.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.2.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.7.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.9.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.3 // indirect
|
||||
github.com/multiformats/go-multistream v0.3.3 // indirect
|
||||
github.com/multiformats/go-multistream v0.4.1 // indirect
|
||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/openrelayxyz/plugeth-utils v1.2.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
|
||||
github.com/pganalyze/pg_query_go/v4 v4.2.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
|
||||
github.com/polydawn/refmt v0.89.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
|
||||
github.com/quic-go/quic-go v0.38.1 // indirect
|
||||
github.com/quic-go/webtransport-go v0.5.3 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
@@ -241,7 +222,6 @@ require (
|
||||
github.com/segmentio/fasthash v1.0.3 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
@@ -249,41 +229,52 @@ require (
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/status-im/keycard-go v0.2.0 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/stretchr/testify v1.8.2 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
|
||||
github.com/thoas/go-funk v0.9.3 // indirect
|
||||
github.com/tidwall/btree v1.6.0 // indirect
|
||||
github.com/tidwall/buntdb v1.2.10 // indirect
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
github.com/tidwall/grect v0.1.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/rtred v0.1.2 // indirect
|
||||
github.com/tidwall/tinyqueue v0.1.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
||||
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
|
||||
github.com/urfave/cli/v2 v2.25.7 // indirect
|
||||
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 // indirect
|
||||
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/dig v1.15.0 // indirect
|
||||
go.uber.org/fx v1.18.2 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/dig v1.17.0 // indirect
|
||||
go.uber.org/fx v1.20.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.25.0 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/term v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
gonum.org/v1/gonum v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
@@ -294,11 +285,21 @@ require (
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/cerc-io/eth-ipfs-state-validator/v5 => git.vdb.to/cerc-io/eth-ipfs-state-validator/v5 v5.1.1-alpha
|
||||
github.com/cerc-io/eth-iterator-utils => git.vdb.to/cerc-io/eth-iterator-utils v0.1.2-beta
|
||||
// github.com/cerc-io/eth-ipfs-state-validator/v5 => git.vdb.to/cerc-io/eth-ipfs-state-validator/v5 v5.1.1-alpha
|
||||
github.com/cerc-io/eth-iterator-utils => git.vdb.to/cerc-io/eth-iterator-utils v0.1.2
|
||||
github.com/cerc-io/eth-testing => git.vdb.to/cerc-io/eth-testing v0.3.1
|
||||
github.com/cerc-io/ipld-eth-statedb => git.vdb.to/cerc-io/ipld-eth-statedb v0.0.7-alpha-0.0.1 // git.vdb.to/cerc-io/ipld-eth-statedb v0.0.6-alpha
|
||||
github.com/cerc-io/ipld-eth-statedb => git.vdb.to/cerc-io/ipld-eth-statedb v0.0.6-alpha
|
||||
github.com/cerc-io/plugeth-statediff => git.vdb.to/cerc-io/plugeth-statediff v0.1.4
|
||||
github.com/ethereum/go-ethereum => git.vdb.to/cerc-io/plugeth v0.0.0-20230808125822-691dc334fab1
|
||||
github.com/openrelayxyz/plugeth-utils => git.vdb.to/cerc-io/plugeth-utils v0.0.0-20230706160122-cd41de354c46
|
||||
)
|
||||
|
||||
// TODO: Use releases after these branches get merged
|
||||
replace (
|
||||
// https://git.vdb.to/cerc-io/eth-ipfs-state-validator/src/branch/v5-go-upgrade
|
||||
github.com/cerc-io/eth-ipfs-state-validator/v5 => github.com/cerc-io/eth-ipfs-state-validator/v5 v5.1.1-alpha.0.20231013075659-56aa03028c43
|
||||
// https://git.vdb.to/cerc-io/ipfs-ethdb/src/branch/v5-go-upgrade
|
||||
github.com/cerc-io/ipfs-ethdb/v5 => github.com/cerc-io/ipfs-ethdb/v5 v5.0.1-alpha.0.20231013070931-0b1a36562a28
|
||||
)
|
||||
|
||||
replace github.com/statechannels/go-nitro v0.1.2 => github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.9
|
||||
|
||||
+1
-46
@@ -27,9 +27,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
||||
statediff "github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -1007,52 +1005,9 @@ func (diff *StateOverride) Apply(state *ipld_direct_state.StateDB) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now finalize the changes. Finalize is normally performed between transactions.
|
||||
// By using finalize, the overrides are semantically behaving as
|
||||
// if they were created in a transaction just before the tracing occur.
|
||||
state.Finalise(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
// BlockOverrides is a set of header fields to override.
|
||||
type BlockOverrides struct {
|
||||
Number *hexutil.Big
|
||||
Difficulty *hexutil.Big
|
||||
Time *hexutil.Uint64
|
||||
GasLimit *hexutil.Uint64
|
||||
Coinbase *common.Address
|
||||
Random *common.Hash
|
||||
BaseFee *hexutil.Big
|
||||
}
|
||||
|
||||
// Apply overrides the given header fields into the given block context.
|
||||
func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
|
||||
if diff == nil {
|
||||
return
|
||||
}
|
||||
if diff.Number != nil {
|
||||
blockCtx.BlockNumber = diff.Number.ToInt()
|
||||
}
|
||||
if diff.Difficulty != nil {
|
||||
blockCtx.Difficulty = diff.Difficulty.ToInt()
|
||||
}
|
||||
if diff.Time != nil {
|
||||
blockCtx.Time = uint64(*diff.Time)
|
||||
}
|
||||
if diff.GasLimit != nil {
|
||||
blockCtx.GasLimit = uint64(*diff.GasLimit)
|
||||
}
|
||||
if diff.Coinbase != nil {
|
||||
blockCtx.Coinbase = *diff.Coinbase
|
||||
}
|
||||
if diff.Random != nil {
|
||||
blockCtx.Random = diff.Random
|
||||
}
|
||||
if diff.BaseFee != nil {
|
||||
blockCtx.BaseFee = diff.BaseFee.ToInt()
|
||||
}
|
||||
}
|
||||
|
||||
// Call executes the given transaction on the state for the given block number.
|
||||
//
|
||||
// Additionally, the caller can specify a batch of contract for fields overriding.
|
||||
|
||||
@@ -1,466 +0,0 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2019 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package eth_debug_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
statediff "github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/cerc-io/plugeth-statediff/adapt"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v5/pkg/eth"
|
||||
"github.com/cerc-io/ipld-eth-server/v5/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
db *sqlx.DB
|
||||
chainConfig = &*params.TestChainConfig
|
||||
mockTD = big.NewInt(1337)
|
||||
ctx = context.Background()
|
||||
tb *testBackend
|
||||
accounts Accounts
|
||||
genBlocks int
|
||||
)
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
// db and type initializations
|
||||
var err error
|
||||
db = shared.SetupDB()
|
||||
|
||||
// Initialize test accounts
|
||||
accounts = newAccounts(3)
|
||||
genesis := &core.Genesis{
|
||||
Config: chainConfig,
|
||||
Alloc: core.GenesisAlloc{
|
||||
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
|
||||
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
|
||||
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
|
||||
},
|
||||
}
|
||||
genBlocks = 10
|
||||
signer := types.HomesteadSigner{}
|
||||
tb, blocks, receipts := newTestBackend(genBlocks, genesis, func(i int, b *core.BlockGen) {
|
||||
// Transfer from account[0] to account[1]
|
||||
// value: 1000 wei
|
||||
// fee: 0 wei
|
||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
||||
b.AddTx(tx)
|
||||
})
|
||||
transformer := shared.SetupTestStateDiffIndexer(ctx, chainConfig, blocks[0].Hash())
|
||||
params := statediff.Params{}
|
||||
|
||||
// iterate over the blocks, generating statediff payloads, and transforming the data into Postgres
|
||||
builder := statediff.NewBuilder(adapt.GethStateView(tb.chain.StateCache()))
|
||||
for i, block := range blocks {
|
||||
var args statediff.Args
|
||||
if i == 0 {
|
||||
args = statediff.Args{
|
||||
OldStateRoot: common.Hash{},
|
||||
NewStateRoot: block.Root(),
|
||||
BlockNumber: block.Number(),
|
||||
BlockHash: block.Hash(),
|
||||
}
|
||||
} else {
|
||||
args = statediff.Args{
|
||||
OldStateRoot: blocks[i-1].Root(),
|
||||
NewStateRoot: block.Root(),
|
||||
BlockNumber: block.Number(),
|
||||
BlockHash: block.Hash(),
|
||||
}
|
||||
}
|
||||
diff, err := builder.BuildStateDiffObject(args, params)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
tx, err := transformer.PushBlock(block, receipts[i], mockTD)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer tx.RollbackOnFailure(err)
|
||||
|
||||
for _, node := range diff.Nodes {
|
||||
err = transformer.PushStateNode(tx, node, block.Hash().String())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, ipld := range diff.IPLDs {
|
||||
err = transformer.PushIPLD(tx, ipld)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = tx.Submit()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
backend, err := eth.NewEthBackend(db, ð.Config{
|
||||
ChainConfig: chainConfig,
|
||||
VMConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||
GroupCacheConfig: &shared.GroupCacheConfig{
|
||||
StateDB: shared.GroupConfig{
|
||||
Name: "eth_debug_test",
|
||||
CacheSizeInMB: 8,
|
||||
CacheExpiryInMins: 60,
|
||||
LogStatsIntervalInSecs: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
tracingAPI, _ = eth.NewTracingAPI(backend, nil, eth.APIConfig{StateDiffTimeout: shared.DefaultStateDiffTimeout})
|
||||
tb.teardown()
|
||||
})
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
shared.TearDownDB(db)
|
||||
})
|
||||
|
||||
var (
|
||||
tracingAPI *eth.TracingAPI
|
||||
)
|
||||
|
||||
var _ = Describe("eth state reading tests", func() {
|
||||
Describe("debug_traceCall", func() {
|
||||
It("Works", func() {
|
||||
var testSuite = []struct {
|
||||
blockNumber rpc.BlockNumber
|
||||
call eth.TransactionArgs
|
||||
config *eth.TraceCallConfig
|
||||
expectErr error
|
||||
expect string
|
||||
}{
|
||||
// Standard JSON trace upon the genesis, plain transfer.
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(0),
|
||||
call: eth.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
},
|
||||
// Standard JSON trace upon the head, plain transfer.
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks),
|
||||
call: eth.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
},
|
||||
// Standard JSON trace upon the non-existent block, error expects
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks + 1),
|
||||
call: eth.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: nil,
|
||||
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
|
||||
//expect: nil,
|
||||
},
|
||||
// Standard JSON trace upon the latest block
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: eth.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: nil,
|
||||
expectErr: nil,
|
||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||
},
|
||||
// Tracing on 'pending' should fail:
|
||||
{
|
||||
blockNumber: rpc.PendingBlockNumber,
|
||||
call: eth.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: nil,
|
||||
expectErr: fmt.Errorf("tracing on top of pending is not supported"),
|
||||
},
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: eth.TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
Input: &hexutil.Bytes{0x43}, // blocknumber
|
||||
},
|
||||
config: ð.TraceCallConfig{
|
||||
BlockOverrides: ð.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
expectErr: nil,
|
||||
expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[
|
||||
{"pc":0,"op":"NUMBER","gas":9999946984,"gasCost":2,"depth":1,"stack":[]},
|
||||
{"pc":1,"op":"STOP","gas":9999946982,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`,
|
||||
},
|
||||
}
|
||||
for _, testspec := range testSuite {
|
||||
result, err := tracingAPI.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config)
|
||||
if testspec.expectErr != nil {
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(Equal(testspec.expectErr))
|
||||
} else {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
var have *logger.ExecutionResult
|
||||
err := json.Unmarshal(result.(json.RawMessage), &have)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
var want *logger.ExecutionResult
|
||||
err = json.Unmarshal([]byte(testspec.expect), &want)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(have).To(Equal(want))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Describe("debug_traceBlock", func() {
|
||||
It("Works", func() {
|
||||
var testSuite = []struct {
|
||||
blockNumber rpc.BlockNumber
|
||||
config *eth.TraceConfig
|
||||
want string
|
||||
expectErr error
|
||||
}{
|
||||
// Trace genesis block, expect error
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(0),
|
||||
expectErr: errors.New("genesis is not traceable"),
|
||||
},
|
||||
// Trace head block
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks),
|
||||
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
|
||||
},
|
||||
// Trace non-existent block
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks + 1),
|
||||
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
|
||||
},
|
||||
// Trace latest block
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
|
||||
},
|
||||
// Trace pending block
|
||||
{
|
||||
blockNumber: rpc.PendingBlockNumber,
|
||||
expectErr: errors.New("pending block number not supported"),
|
||||
},
|
||||
}
|
||||
for _, tc := range testSuite {
|
||||
result, err := tracingAPI.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config)
|
||||
if tc.expectErr != nil {
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(Equal(tc.expectErr))
|
||||
} else {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
have, _ := json.Marshal(result)
|
||||
want := tc.want
|
||||
Expect(string(have)).To(Equal(want))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
type testBackend struct {
|
||||
chainConfig *params.ChainConfig
|
||||
engine consensus.Engine
|
||||
chaindb ethdb.Database
|
||||
chain *core.BlockChain
|
||||
|
||||
refHook func() // Hook is invoked when the requested state is referenced
|
||||
relHook func() // Hook is invoked when the requested state is released
|
||||
}
|
||||
|
||||
func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||
return b.chain.GetHeaderByHash(hash), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
|
||||
if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
|
||||
return b.chain.CurrentHeader(), nil
|
||||
}
|
||||
return b.chain.GetHeaderByNumber(uint64(number)), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||
return b.chain.GetBlockByHash(hash), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
|
||||
if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
|
||||
return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil
|
||||
}
|
||||
return b.chain.GetBlockByNumber(uint64(number)), nil
|
||||
}
|
||||
|
||||
func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
||||
tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
|
||||
return tx, hash, blockNumber, index, nil
|
||||
}
|
||||
|
||||
func (b *testBackend) RPCGasCap() uint64 {
|
||||
return 25000000
|
||||
}
|
||||
|
||||
func (b *testBackend) ChainConfig() *params.ChainConfig {
|
||||
return b.chainConfig
|
||||
}
|
||||
|
||||
func (b *testBackend) Engine() consensus.Engine {
|
||||
return b.engine
|
||||
}
|
||||
|
||||
func (b *testBackend) ChainDb() ethdb.Database {
|
||||
return b.chaindb
|
||||
}
|
||||
|
||||
// teardown releases the associated resources.
|
||||
func (b *testBackend) teardown() {
|
||||
b.chain.Stop()
|
||||
}
|
||||
|
||||
var (
|
||||
errStateNotFound = errors.New("state not found")
|
||||
errBlockNotFound = errors.New("block not found")
|
||||
)
|
||||
|
||||
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
statedb, err := b.chain.StateAt(block.Root())
|
||||
if err != nil {
|
||||
return nil, nil, errStateNotFound
|
||||
}
|
||||
if b.refHook != nil {
|
||||
b.refHook()
|
||||
}
|
||||
release := func() {
|
||||
if b.relHook != nil {
|
||||
b.relHook()
|
||||
}
|
||||
}
|
||||
return statedb, release, nil
|
||||
}
|
||||
|
||||
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
||||
}
|
||||
statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false)
|
||||
if err != nil {
|
||||
return nil, vm.BlockContext{}, nil, nil, errStateNotFound
|
||||
}
|
||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||
return nil, vm.BlockContext{}, statedb, release, nil
|
||||
}
|
||||
// Recompute transactions up to the target index.
|
||||
signer := types.MakeSigner(b.chainConfig, block.Number())
|
||||
for idx, tx := range block.Transactions() {
|
||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||
if idx == txIndex {
|
||||
return msg, context, statedb, release, nil
|
||||
}
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||
}
|
||||
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
}
|
||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
|
||||
}
|
||||
|
||||
// testBackend creates a new test backend. OBS: After test is done, teardown must be
|
||||
// invoked in order to release associated resources.
|
||||
func newTestBackend(n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) (*testBackend, types.Blocks, []types.Receipts) {
|
||||
backend := &testBackend{
|
||||
chainConfig: gspec.Config,
|
||||
engine: ethash.NewFaker(),
|
||||
chaindb: rawdb.NewMemoryDatabase(),
|
||||
}
|
||||
// Generate blocks for testing
|
||||
_, blocks, receipts := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator)
|
||||
|
||||
// Import the canonical chain
|
||||
cacheConfig := &core.CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 0,
|
||||
TrieDirtyDisabled: true, // Archive mode
|
||||
}
|
||||
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
n, err = chain.InsertChain(blocks)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
backend.chain = chain
|
||||
return backend, blocks, receipts
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
key *ecdsa.PrivateKey
|
||||
addr common.Address
|
||||
}
|
||||
|
||||
type Accounts []Account
|
||||
|
||||
func (a Accounts) Len() int { return len(a) }
|
||||
func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 }
|
||||
|
||||
func newAccounts(n int) (accounts Accounts) {
|
||||
for i := 0; i < n; i++ {
|
||||
key, _ := crypto.GenerateKey()
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
accounts = append(accounts, Account{key: key, addr: addr})
|
||||
}
|
||||
sort.Sort(accounts)
|
||||
return accounts
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2019 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package eth_debug_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestETHSuite(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "ipld-eth-server/pkg/eth/state_test")
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
statediff "github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/cerc-io/plugeth-statediff/adapt"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
statediff "github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/cerc-io/plugeth-statediff"
|
||||
"github.com/cerc-io/plugeth-statediff/adapt"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultTraceTimeout is the amount of time a single transaction can execute
|
||||
// by default before being forcefully aborted.
|
||||
defaultTraceTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// TracingAPI is the collection of tracing APIs exposed over the private debugging endpoint.
|
||||
type TracingAPI struct {
|
||||
backend *Backend
|
||||
rpc *rpc.Client
|
||||
config APIConfig
|
||||
}
|
||||
|
||||
// NewTracingAPI creates a new TracingAPI with the provided underlying Backend
|
||||
func NewTracingAPI(b *Backend, client *rpc.Client, config APIConfig) (*TracingAPI, error) {
|
||||
if b == nil {
|
||||
return nil, errors.New("ipld-eth-server must be configured with an ethereum backend")
|
||||
}
|
||||
if config.ForwardEthCalls && client == nil {
|
||||
return nil, errors.New("ipld-eth-server is configured to forward eth_calls to proxy node but no proxy node is configured")
|
||||
}
|
||||
if config.ForwardGetStorageAt && client == nil {
|
||||
return nil, errors.New("ipld-eth-server is configured to forward eth_getStorageAt to proxy node but no proxy node is configured")
|
||||
}
|
||||
if config.ProxyOnError && client == nil {
|
||||
return nil, errors.New("ipld-eth-server is configured to forward all calls to proxy node on errors but no proxy node is configured")
|
||||
}
|
||||
return &TracingAPI{
|
||||
backend: b,
|
||||
rpc: client,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TraceConfig holds extra parameters to trace functions.
|
||||
type TraceConfig struct {
|
||||
*logger.Config
|
||||
Tracer *string
|
||||
Timeout *string
|
||||
Reexec *uint64
|
||||
// Config specific to given tracer. Note struct logger
|
||||
// config are historically embedded in main object.
|
||||
TracerConfig json.RawMessage
|
||||
}
|
||||
|
||||
// TraceCallConfig is the config for traceCall API. It holds one more
|
||||
// field to override the state for tracing.
|
||||
type TraceCallConfig struct {
|
||||
TraceConfig
|
||||
StateOverrides *StateOverride
|
||||
BlockOverrides *BlockOverrides
|
||||
}
|
||||
|
||||
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
||||
// created during the execution of EVM if the given transaction was added on
|
||||
// top of the provided block and returns them as a JSON object.
|
||||
func (api *TracingAPI) TraceCall(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
|
||||
trace, err := api.localTraceCall(ctx, args, blockNrOrHash, config)
|
||||
if trace != nil && err == nil {
|
||||
return trace, nil
|
||||
}
|
||||
if api.config.ProxyOnError {
|
||||
var res interface{}
|
||||
if err := api.rpc.CallContext(ctx, &res, "debug_traceCall", args, blockNrOrHash, config); res != nil && err == nil {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (api *TracingAPI) localTraceCall(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
|
||||
// Try to retrieve the specified block
|
||||
var (
|
||||
err error
|
||||
block *types.Block
|
||||
)
|
||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||
block, err = api.blockByHash(ctx, hash)
|
||||
} else if number, ok := blockNrOrHash.Number(); ok {
|
||||
if number == rpc.PendingBlockNumber {
|
||||
// We don't have access to the miner here. For tracing 'future' transactions,
|
||||
// it can be done with block- and state-overrides instead, which offers
|
||||
// more flexibility and stability than trying to trace on 'pending', since
|
||||
// the contents of 'pending' is unstable and probably not a true representation
|
||||
// of what the next actual block is likely to contain.
|
||||
return nil, errors.New("tracing on top of pending is not supported")
|
||||
}
|
||||
block, err = api.blockByNumber(ctx, number)
|
||||
} else {
|
||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stateDB, _, err := api.backend.IPLDDirectStateDBAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithHash(block.Hash(), true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
// Apply the customization rules if required.
|
||||
if config != nil {
|
||||
if err := config.StateOverrides.Apply(stateDB); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.BlockOverrides.Apply(&vmctx)
|
||||
}
|
||||
// Execute the trace
|
||||
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var traceConfig *TraceConfig
|
||||
if config != nil {
|
||||
traceConfig = &config.TraceConfig
|
||||
}
|
||||
return api.traceTx(ctx, msg, new(tracers.Context), vmctx, stateDB, traceConfig)
|
||||
}
|
||||
|
||||
// traceTx configures a new tracer according to the provided configuration, and
|
||||
// executes the given message in the provided environment. The return value will
|
||||
// be tracer dependent.
|
||||
func (api *TracingAPI) traceTx(ctx context.Context, message *core.Message, txctx *tracers.Context, vmctx vm.BlockContext, statedb *ipld_direct_state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||
var (
|
||||
tracer tracers.Tracer
|
||||
err error
|
||||
timeout = defaultTraceTimeout
|
||||
txContext = core.NewEVMTxContext(message)
|
||||
)
|
||||
if config == nil {
|
||||
config = &TraceConfig{}
|
||||
}
|
||||
// Default tracer is the struct logger
|
||||
tracer = logger.NewStructLogger(config.Config)
|
||||
if config.Tracer != nil {
|
||||
tracer, err = tracers.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
|
||||
|
||||
// Define a meaningful timeout of a single transaction trace
|
||||
if config.Timeout != nil {
|
||||
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
go func() {
|
||||
<-deadlineCtx.Done()
|
||||
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
|
||||
tracer.Stop(errors.New("execution timeout"))
|
||||
// Stop evm execution. Note cancellation is not necessarily immediate.
|
||||
vmenv.Cancel()
|
||||
}
|
||||
}()
|
||||
defer cancel()
|
||||
|
||||
// Call Prepare to clear out the statedb access list
|
||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
|
||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||
}
|
||||
return tracer.GetResult()
|
||||
}
|
||||
|
||||
// chainContext constructs the context reader which is used by the evm for reading
|
||||
// the necessary chain context.
|
||||
func (api *TracingAPI) chainContext(ctx context.Context) core.ChainContext {
|
||||
return &chainContext{api: api, ctx: ctx}
|
||||
}
|
||||
|
||||
// blockByNumber is the wrapper of the chain access function offered by the backend.
|
||||
// It will return an error if the block is not found.
|
||||
func (api *TracingAPI) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
|
||||
block, err := api.backend.BlockByNumber(ctx, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// blockByHash is the wrapper of the chain access function offered by the backend.
|
||||
// It will return an error if the block is not found.
|
||||
func (api *TracingAPI) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||
block, err := api.backend.BlockByHash(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block %s not found", hash.Hex())
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// txTraceTask represents a single transaction trace task when an entire block
|
||||
// is being traced.
|
||||
type txTraceTask struct {
|
||||
statedb *ipld_direct_state.StateDB // Intermediate state prepped for tracing
|
||||
index int // Transaction offset in the block
|
||||
}
|
||||
|
||||
// txTraceResult is the result of a single transaction trace.
|
||||
type txTraceResult struct {
|
||||
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
||||
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
|
||||
}
|
||||
|
||||
var noGenesisErr = errors.New("genesis is not traceable")
|
||||
|
||||
// TraceBlockByNumber returns the structured logs created during the execution of
|
||||
// EVM and returns them as a JSON object.
|
||||
func (api *TracingAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
if number == 0 {
|
||||
return nil, noGenesisErr
|
||||
}
|
||||
block, err := api.blockByNumber(ctx, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trace, err := api.traceBlock(ctx, block, config)
|
||||
if trace != nil && err == nil {
|
||||
return trace, nil
|
||||
}
|
||||
if api.config.ProxyOnError {
|
||||
var res []*txTraceResult
|
||||
if err := api.rpc.CallContext(ctx, &res, "debug_traceBlockByNumber", number, config); res != nil && err == nil {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TraceBlockByHash returns the structured logs created during the execution of
|
||||
// EVM and returns them as a JSON object.
|
||||
func (api *TracingAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
block, err := api.blockByHash(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block.NumberU64() == 0 {
|
||||
return nil, noGenesisErr
|
||||
}
|
||||
trace, err := api.traceBlock(ctx, block, config)
|
||||
if trace != nil && err == nil {
|
||||
return trace, nil
|
||||
}
|
||||
if api.config.ProxyOnError {
|
||||
var res []*txTraceResult
|
||||
if err := api.rpc.CallContext(ctx, &res, "debug_traceBlockByHash", hash, config); res != nil && err == nil {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TraceBlock returns the structured logs created during the execution of EVM
|
||||
// and returns them as a JSON object.
|
||||
func (api *TracingAPI) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
trace, err := api.localTraceBlock(ctx, blob, config)
|
||||
if trace != nil && err == nil {
|
||||
return trace, nil
|
||||
}
|
||||
if api.config.ProxyOnError {
|
||||
var res []*txTraceResult
|
||||
if err := api.rpc.CallContext(ctx, &res, "debug_traceBlock", blob, config); res != nil && err == nil {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (api *TracingAPI) localTraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
block := new(types.Block)
|
||||
if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
|
||||
return nil, fmt.Errorf("could not decode block: %v", err)
|
||||
}
|
||||
return api.traceBlock(ctx, block, config)
|
||||
}
|
||||
|
||||
// traceBlock configures a new tracer according to the provided configuration, and
|
||||
// executes all the transactions contained within. The return value will be one item
|
||||
// per transaction, dependent on the requested tracer.
|
||||
func (api *TracingAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
if block.NumberU64() == 0 {
|
||||
return nil, errors.New("genesis is not traceable")
|
||||
}
|
||||
stateDB, _, err := api.backend.IPLDDirectStateDBAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithHash(block.ParentHash(), true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// JS tracers have high overhead. In this case run a parallel
|
||||
// process that generates states in one thread and traces txes
|
||||
// in separate worker threads.
|
||||
if config != nil && config.Tracer != nil && *config.Tracer != "" {
|
||||
if isJS := tracers.DefaultDirectory.IsJS(*config.Tracer); isJS {
|
||||
return api.traceBlockParallel(ctx, block, stateDB, config)
|
||||
}
|
||||
}
|
||||
// Native tracers have low overhead
|
||||
var (
|
||||
txs = block.Transactions()
|
||||
blockHash = block.Hash()
|
||||
is158 = api.backend.ChainConfig().IsEIP158(block.Number())
|
||||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||
results = make([]*txTraceResult, len(txs))
|
||||
)
|
||||
for i, tx := range txs {
|
||||
// Generate the next state snapshot fast without tracing
|
||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||
txctx := &tracers.Context{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: block.Number(),
|
||||
TxIndex: i,
|
||||
TxHash: tx.Hash(),
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, stateDB, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results[i] = &txTraceResult{Result: res}
|
||||
// Finalize the state so any modifications are written to the trie
|
||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||
stateDB.Finalise(is158)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread
|
||||
// runs along and executes txes without tracing enabled to generate their prestate.
|
||||
// Worker threads take the tasks and the prestate and trace them.
|
||||
func (api *TracingAPI) traceBlockParallel(ctx context.Context, block *types.Block, statedb *ipld_direct_state.StateDB, config *TraceConfig) ([]*txTraceResult, error) {
|
||||
// Execute all the transaction contained within the block concurrently
|
||||
var (
|
||||
txs = block.Transactions()
|
||||
blockHash = block.Hash()
|
||||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||
results = make([]*txTraceResult, len(txs))
|
||||
pend sync.WaitGroup
|
||||
)
|
||||
threads := runtime.NumCPU()
|
||||
if threads > len(txs) {
|
||||
threads = len(txs)
|
||||
}
|
||||
jobs := make(chan *txTraceTask, threads)
|
||||
for th := 0; th < threads; th++ {
|
||||
pend.Add(1)
|
||||
go func() {
|
||||
defer pend.Done()
|
||||
// Fetch and execute the next transaction trace tasks
|
||||
for task := range jobs {
|
||||
msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
|
||||
txctx := &tracers.Context{
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: block.Number(),
|
||||
TxIndex: task.index,
|
||||
TxHash: txs[task.index].Hash(),
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
|
||||
if err != nil {
|
||||
results[task.index] = &txTraceResult{Error: err.Error()}
|
||||
continue
|
||||
}
|
||||
results[task.index] = &txTraceResult{Result: res}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Feed the transactions into the tracers and return
|
||||
var failed error
|
||||
txloop:
|
||||
for i, tx := range txs {
|
||||
// Send the trace task over for execution
|
||||
task := &txTraceTask{statedb: statedb.Copy(), index: i}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
failed = ctx.Err()
|
||||
break txloop
|
||||
case jobs <- task:
|
||||
}
|
||||
|
||||
// Generate the next state snapshot fast without tracing
|
||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||
failed = err
|
||||
break txloop
|
||||
}
|
||||
// Finalize the state so any modifications are written to the trie
|
||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
||||
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||
}
|
||||
|
||||
close(jobs)
|
||||
pend.Wait()
|
||||
|
||||
// If execution failed in between, abort
|
||||
if failed != nil {
|
||||
return nil, failed
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// blockByNumberAndHash is the wrapper of the chain access function offered by
|
||||
// the backend. It will return an error if the block is not found.
|
||||
//
|
||||
// Note this function is friendly for the light client which can only retrieve the
|
||||
// historical(before the CHT) header/block by number.
|
||||
func (api *TracingAPI) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
|
||||
block, err := api.blockByNumber(ctx, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block.Hash() == hash {
|
||||
return block, nil
|
||||
}
|
||||
return api.blockByHash(ctx, hash)
|
||||
}
|
||||
|
||||
type chainContext struct {
|
||||
api *TracingAPI
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (context *chainContext) Engine() consensus.Engine {
|
||||
return context.api.backend.Engine()
|
||||
}
|
||||
|
||||
func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if header.Hash() == hash {
|
||||
return header
|
||||
}
|
||||
header, err = context.api.backend.HeaderByHash(context.ctx, hash)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return header
|
||||
}
|
||||
@@ -1,15 +1,9 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// TransactionArgs represents the arguments to construct a new transaction
|
||||
@@ -53,85 +47,3 @@ func (args *TransactionArgs) data() []byte {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToMessage converts the transaction arguments to the Message type used by the
|
||||
// core evm. This method is used in calls and traces that do not require a real
|
||||
// live transaction.
|
||||
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) {
|
||||
// Reject invalid combinations of pre- and post-1559 fee styles
|
||||
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
||||
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||
}
|
||||
// Set sender address or use zero address if none specified.
|
||||
addr := args.from()
|
||||
|
||||
// Set default gas & gas price if none were set
|
||||
gas := globalGasCap
|
||||
if gas == 0 {
|
||||
gas = uint64(math.MaxUint64 / 2)
|
||||
}
|
||||
if args.Gas != nil {
|
||||
gas = uint64(*args.Gas)
|
||||
}
|
||||
if globalGasCap != 0 && globalGasCap < gas {
|
||||
logrus.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
|
||||
gas = globalGasCap
|
||||
}
|
||||
var (
|
||||
gasPrice *big.Int
|
||||
gasFeeCap *big.Int
|
||||
gasTipCap *big.Int
|
||||
)
|
||||
if baseFee == nil {
|
||||
// If there's no basefee, then it must be a non-1559 execution
|
||||
gasPrice = new(big.Int)
|
||||
if args.GasPrice != nil {
|
||||
gasPrice = args.GasPrice.ToInt()
|
||||
}
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// A basefee is provided, necessitating 1559-type execution
|
||||
if args.GasPrice != nil {
|
||||
// User specified the legacy gas field, convert to 1559 gas typing
|
||||
gasPrice = args.GasPrice.ToInt()
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// User specified 1559 gas fields (or none), use those
|
||||
gasFeeCap = new(big.Int)
|
||||
if args.MaxFeePerGas != nil {
|
||||
gasFeeCap = args.MaxFeePerGas.ToInt()
|
||||
}
|
||||
gasTipCap = new(big.Int)
|
||||
if args.MaxPriorityFeePerGas != nil {
|
||||
gasTipCap = args.MaxPriorityFeePerGas.ToInt()
|
||||
}
|
||||
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
|
||||
gasPrice = new(big.Int)
|
||||
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
|
||||
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
|
||||
}
|
||||
}
|
||||
}
|
||||
value := new(big.Int)
|
||||
if args.Value != nil {
|
||||
value = args.Value.ToInt()
|
||||
}
|
||||
data := args.data()
|
||||
var accessList types.AccessList
|
||||
if args.AccessList != nil {
|
||||
accessList = *args.AccessList
|
||||
}
|
||||
msg := &core.Message{
|
||||
From: addr,
|
||||
To: args.To,
|
||||
Value: value,
|
||||
GasLimit: gas,
|
||||
GasPrice: gasPrice,
|
||||
GasFeeCap: gasFeeCap,
|
||||
GasTipCap: gasTipCap,
|
||||
Data: data,
|
||||
AccessList: accessList,
|
||||
SkipAccountChecks: true,
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
+11
-3
@@ -18,6 +18,7 @@ package rpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v5/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
@@ -28,16 +29,23 @@ import (
|
||||
)
|
||||
|
||||
// StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules.
|
||||
func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) (*rpc.Server, error) {
|
||||
|
||||
func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, httpMiddlewares [](func(next http.Handler) http.Handler)) (*rpc.Server, error) {
|
||||
srv := rpc.NewServer()
|
||||
err := node.RegisterApis(apis, modules, srv)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not register HTTP API: %w", err)
|
||||
}
|
||||
handler := prom.HTTPMiddleware(node.NewHTTPHandlerStack(srv, cors, vhosts, nil))
|
||||
|
||||
promHandler := prom.HTTPMiddleware(node.NewHTTPHandlerStack(srv, cors, vhosts, nil))
|
||||
|
||||
// Chain the HTTP middlewares
|
||||
handler := promHandler
|
||||
for _, middleware := range httpMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
// start http server
|
||||
// request -> payments -> metrics -> server
|
||||
_, addr, err := node.StartHTTPEndpoint(endpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not start RPC api: %v", err)
|
||||
|
||||
+98
-4
@@ -79,8 +79,56 @@ const (
|
||||
DATABASE_MAX_IDLE_CONNECTIONS = "DATABASE_MAX_IDLE_CONNECTIONS"
|
||||
DATABASE_MAX_OPEN_CONNECTIONS = "DATABASE_MAX_OPEN_CONNECTIONS"
|
||||
DATABASE_MAX_CONN_LIFETIME = "DATABASE_MAX_CONN_LIFETIME"
|
||||
|
||||
NITRO_RUN_NODE_IN_PROCESS = "NITRO_RUN_NODE_IN_PROCESS"
|
||||
NITRO_RPC_QUERY_RATES_FILE = "NITRO_RPC_QUERY_RATES_FILE"
|
||||
NITRO_PK = "NITRO_PK"
|
||||
NITRO_CHAIN_PK = "NITRO_CHAIN_PK"
|
||||
NITRO_CHAIN_URL = "NITRO_CHAIN_URL"
|
||||
NITRO_NA_ADDRESS = "NITRO_NA_ADDRESS"
|
||||
NITRO_VPA_ADDRESS = "NITRO_VPA_ADDRESS"
|
||||
NITRO_CA_ADDRESS = "NITRO_CA_ADDRESS"
|
||||
NITRO_USE_DURABLE_STORE = "NITRO_USE_DURABLE_STORE"
|
||||
NITRO_DURABLE_STORE_FOLDER = "NITRO_DURABLE_STORE_FOLDER"
|
||||
NITRO_ENDPOINT = "NITRO_ENDPOINT"
|
||||
NITRO_IS_SECURE = "NITRO_IS_SECURE"
|
||||
NITRO_MSG_PORT = "NITRO_MSG_PORT"
|
||||
NITRO_WS_MSG_PORT = "NITRO_WS_MSG_PORT"
|
||||
NITRO_RPC_PORT = "NITRO_RPC_PORT"
|
||||
NITRO_CHAIN_START_BLOCK = "NITRO_CHAIN_START_BLOCK"
|
||||
NITRO_TLS_CERT_FILEPATH = "NITRO_TLS_CERT_FILEPATH"
|
||||
NITRO_TLS_KEY_FILEPATH = "NITRO_TLS_KEY_FILEPATH"
|
||||
)
|
||||
|
||||
type InProcessNitroNodeConfig struct {
|
||||
Pk string
|
||||
ChainPk string
|
||||
ChainUrl string
|
||||
NaAddress string
|
||||
VpaAddress string
|
||||
CaAddress string
|
||||
UseDurableStore bool
|
||||
DurableStoreFolder string
|
||||
RpcPort int
|
||||
MsgPort int
|
||||
WsMsgPort int
|
||||
ChainStartBlock uint64
|
||||
TlsCertFilepath string
|
||||
TlsKeyFilepath string
|
||||
}
|
||||
|
||||
type RemoteNitroNodeConfig struct {
|
||||
NitroEndpoint string
|
||||
IsSecure bool
|
||||
}
|
||||
|
||||
type NitroConfig struct {
|
||||
RunNodeInProcess bool
|
||||
RpcQueryRatesFile string
|
||||
InProcessNode InProcessNitroNodeConfig
|
||||
RemoteNode RemoteNitroNodeConfig
|
||||
}
|
||||
|
||||
// Config struct
|
||||
type Config struct {
|
||||
DB *sqlx.DB
|
||||
@@ -110,14 +158,14 @@ type Config struct {
|
||||
ProxyOnError bool
|
||||
GetLogsBlockLimit int64
|
||||
NodeNetworkID string
|
||||
TracingEnabled bool
|
||||
TracingPublic bool
|
||||
|
||||
// Cache configuration.
|
||||
GroupCache *ethServerShared.GroupCacheConfig
|
||||
|
||||
StateValidationEnabled bool
|
||||
StateValidationEveryNthBlock uint64
|
||||
|
||||
Nitro *NitroConfig
|
||||
}
|
||||
|
||||
// NewConfig is used to initialize a watcher config from a .toml file
|
||||
@@ -156,8 +204,6 @@ func NewConfig() (*Config, error) {
|
||||
c.ForwardGetStorageAt = viper.GetBool("ethereum.forwardGetStorageAt")
|
||||
c.ProxyOnError = viper.GetBool("ethereum.proxyOnError")
|
||||
c.EthHttpEndpoint = ethHTTPEndpoint
|
||||
c.TracingEnabled = viper.GetBool("ethereum.tracingEnabled")
|
||||
c.TracingPublic = viper.GetBool("ethereum.tracingPublic")
|
||||
|
||||
if viper.IsSet("ethereum.getLogsBlockLimit") {
|
||||
c.GetLogsBlockLimit = viper.GetInt64("ethereum.getLogsBlockLimit")
|
||||
@@ -252,6 +298,8 @@ func NewConfig() (*Config, error) {
|
||||
|
||||
c.loadValidatorConfig()
|
||||
|
||||
c.loadNitroConfig()
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
||||
@@ -284,6 +332,52 @@ func (c *Config) dbInit() {
|
||||
c.DBConfig.MaxConnLifetime = time.Duration(viper.GetInt("database.maxLifetime"))
|
||||
}
|
||||
|
||||
func (c *Config) loadNitroConfig() {
|
||||
c.Nitro = &NitroConfig{InProcessNode: InProcessNitroNodeConfig{}, RemoteNode: RemoteNitroNodeConfig{}}
|
||||
|
||||
viper.BindEnv("nitro.runNodeInProcess", NITRO_RUN_NODE_IN_PROCESS)
|
||||
viper.BindEnv("nitro.rpcQueryRatesFile", NITRO_RPC_QUERY_RATES_FILE)
|
||||
|
||||
viper.BindEnv("nitro.inProcesssNode.pk", NITRO_PK)
|
||||
viper.BindEnv("nitro.inProcesssNode.chainPk", NITRO_CHAIN_PK)
|
||||
viper.BindEnv("nitro.inProcesssNode.chainUrl", NITRO_CHAIN_URL)
|
||||
viper.BindEnv("nitro.inProcesssNode.naAddress", NITRO_NA_ADDRESS)
|
||||
viper.BindEnv("nitro.inProcesssNode.vpaAddress", NITRO_VPA_ADDRESS)
|
||||
viper.BindEnv("nitro.inProcesssNode.caAddress", NITRO_CA_ADDRESS)
|
||||
viper.BindEnv("nitro.inProcesssNode.useDurableStore", NITRO_USE_DURABLE_STORE)
|
||||
viper.BindEnv("nitro.inProcesssNode.durableStoreFolder", NITRO_DURABLE_STORE_FOLDER)
|
||||
viper.BindEnv("nitro.inProcesssNode.msgPort", NITRO_MSG_PORT)
|
||||
viper.BindEnv("nitro.inProcesssNode.rpcPort", NITRO_RPC_PORT)
|
||||
viper.BindEnv("nitro.inProcesssNode.wsMsgPort", NITRO_WS_MSG_PORT)
|
||||
viper.BindEnv("nitro.inProcesssNode.chainStartBlock", NITRO_CHAIN_START_BLOCK)
|
||||
viper.BindEnv("nitro.inProcesssNode.tlsCertFilepath", NITRO_TLS_CERT_FILEPATH)
|
||||
viper.BindEnv("nitro.inProcesssNode.tlsKeyFilepath", NITRO_TLS_KEY_FILEPATH)
|
||||
|
||||
viper.BindEnv("nitro.remoteNode.nitroEndpoint", NITRO_ENDPOINT)
|
||||
viper.BindEnv("nitro.remoteNode.isSecure", NITRO_IS_SECURE)
|
||||
|
||||
c.Nitro.RunNodeInProcess = viper.GetBool("nitro.runNodeInProcess")
|
||||
c.Nitro.RpcQueryRatesFile = viper.GetString("nitro.rpcQueryRatesFile")
|
||||
|
||||
c.Nitro.InProcessNode.Pk = viper.GetString("nitro.inProcesssNode.pk")
|
||||
c.Nitro.InProcessNode.ChainPk = viper.GetString("nitro.inProcesssNode.chainPk")
|
||||
c.Nitro.InProcessNode.ChainUrl = viper.GetString("nitro.inProcesssNode.chainUrl")
|
||||
c.Nitro.InProcessNode.NaAddress = viper.GetString("nitro.inProcesssNode.naAddress")
|
||||
c.Nitro.InProcessNode.VpaAddress = viper.GetString("nitro.inProcesssNode.vpaAddress")
|
||||
c.Nitro.InProcessNode.CaAddress = viper.GetString("nitro.inProcesssNode.caAddress")
|
||||
c.Nitro.InProcessNode.UseDurableStore = viper.GetBool("nitro.inProcesssNode.useDurableStore")
|
||||
c.Nitro.InProcessNode.DurableStoreFolder = viper.GetString("nitro.inProcesssNode.durableStoreFolder")
|
||||
c.Nitro.InProcessNode.MsgPort = viper.GetInt("nitro.inProcesssNode.msgPort")
|
||||
c.Nitro.InProcessNode.RpcPort = viper.GetInt("nitro.inProcesssNode.rpcPort")
|
||||
c.Nitro.InProcessNode.WsMsgPort = viper.GetInt("nitro.inProcesssNode.wsMsgPort")
|
||||
c.Nitro.InProcessNode.ChainStartBlock = viper.GetUint64("nitro.inProcesssNode.chainStartBlock")
|
||||
c.Nitro.InProcessNode.TlsCertFilepath = viper.GetString("nitro.inProcesssNode.tlsCertFilepath")
|
||||
c.Nitro.InProcessNode.TlsKeyFilepath = viper.GetString("nitro.inProcesssNode.tlsKeyFilepath")
|
||||
|
||||
c.Nitro.RemoteNode.NitroEndpoint = viper.GetString("nitro.remoteNode.nitroEndpoint")
|
||||
c.Nitro.RemoteNode.IsSecure = viper.GetBool("nitro.remoteNode.isSecure")
|
||||
}
|
||||
|
||||
func (c *Config) loadGroupCacheConfig() {
|
||||
viper.BindEnv("groupcache.pool.enabled", ethServerShared.GcachePoolEnabled)
|
||||
viper.BindEnv("groupcache.pool.httpEndpoint", ethServerShared.GcachePoolHttpPath)
|
||||
|
||||
+1
-24
@@ -78,10 +78,6 @@ type Service struct {
|
||||
proxyOnError bool
|
||||
// eth node network id
|
||||
nodeNetworkId string
|
||||
// tracing enabled
|
||||
tracingEnabled bool
|
||||
// tracing public
|
||||
tracingPublic bool
|
||||
}
|
||||
|
||||
// NewServer creates a new Server using an underlying Service struct
|
||||
@@ -97,8 +93,6 @@ func NewServer(settings *Config) (Server, error) {
|
||||
sap.getLogsBlockLimit = settings.GetLogsBlockLimit
|
||||
sap.proxyOnError = settings.ProxyOnError
|
||||
sap.nodeNetworkId = settings.NodeNetworkID
|
||||
sap.tracingEnabled = settings.TracingEnabled
|
||||
sap.tracingPublic = settings.TracingPublic
|
||||
var err error
|
||||
sap.backend, err = eth.NewEthBackend(sap.db, ð.Config{
|
||||
ChainConfig: settings.ChainConfig,
|
||||
@@ -144,10 +138,9 @@ func (sap *Service) APIs() []rpc.API {
|
||||
log.Fatalf("unable to create public eth api: %v", err)
|
||||
}
|
||||
|
||||
// this uses stubbed StateAtBlock and StateAtTransaction methods and so does not support debug_traceBlock and debug_traceCall
|
||||
debugTracerAPI := tracers.APIs(&debug.Backend{Backend: *sap.backend})[0]
|
||||
|
||||
apis = append(apis,
|
||||
return append(apis,
|
||||
rpc.API{
|
||||
Namespace: eth.APIName,
|
||||
Version: eth.APIVersion,
|
||||
@@ -156,22 +149,6 @@ func (sap *Service) APIs() []rpc.API {
|
||||
},
|
||||
debugTracerAPI,
|
||||
)
|
||||
|
||||
if sap.tracingEnabled {
|
||||
tracingAPI, err := eth.NewTracingAPI(sap.backend, sap.client, conf)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create tracing api: %v", err)
|
||||
}
|
||||
apis = append(apis, rpc.API{
|
||||
// Uses same namespace as stubbed debug API above
|
||||
// Need to test if this will properly overlay and form a union with the existing methods supported by that
|
||||
// Or if only one is exposed
|
||||
Namespace: "debug",
|
||||
Service: tracingAPI,
|
||||
Public: sap.tracingPublic,
|
||||
})
|
||||
}
|
||||
return apis
|
||||
}
|
||||
|
||||
// Serve listens for incoming converter data off the screenAndServePayload from the Sync process
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ services:
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- ipld-eth-db
|
||||
image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v5.2.1-alpha
|
||||
image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v5.0.5-alpha
|
||||
environment:
|
||||
DATABASE_USER: "vdbm"
|
||||
DATABASE_NAME: "cerc_testing"
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
git.vdb.to/cerc-io/ipld-eth-db v5.2.1-alpha
|
||||
github.com/cerc-io/ipld-eth-db v5.0.5-alpha
|
||||
git.vdb.to/cerc-io/plugeth-statediff v0.1.1
|
||||
|
||||
Reference in New Issue
Block a user