diff --git a/.github/workflows/mamoru-build-test.yml b/.github/workflows/mamoru-build-test.yml index 0770233952..3df732c24f 100644 --- a/.github/workflows/mamoru-build-test.yml +++ b/.github/workflows/mamoru-build-test.yml @@ -38,12 +38,13 @@ jobs: restore-keys: | ${{ runner.os }}-go- -# - name: Setup SSH for Private Repository Access -# uses: webfactory/ssh-agent@v0.9.0 -# with: -# ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + - name: Setup SSH for Private Repository Access + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.MAMORU_ETHERMINT_SSH_PRIVATE_KEY }} - name: Test and Build with Makefile run: | + export GOPRIVATE=github.com/Mamoru-Foundation/* go mod download make build diff --git a/.github/workflows/mamoru-docker.yml b/.github/workflows/mamoru-docker.yml index 991461fd91..d503c4bf6d 100644 --- a/.github/workflows/mamoru-docker.yml +++ b/.github/workflows/mamoru-docker.yml @@ -30,14 +30,14 @@ jobs: id: date run: echo "::set-output name=date::$(date -u +'%Y-%m-%d')" -# - uses: webfactory/ssh-agent@v0.9.0 -# with: -# ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} -# -# - name: Prepare git and ssh config for build context -# run: | -# mkdir -p root-config -# cp -r ~/.gitconfig ~/.ssh root-config/ + - uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.MAMORU_ETHERMINT_SSH_PRIVATE_KEY }} + + - name: Prepare git and ssh config for build context + run: | + mkdir -p root-config + cp -r ~/.gitconfig ~/.ssh root-config/ - name: Build and push uses: docker/build-push-action@v3 @@ -53,5 +53,5 @@ jobs: tags: | ${{ env.REPOSITORY }}:latest ${{ env.REPOSITORY }}:${{ github.sha }} -# ssh: | -# default=${{ env.SSH_AUTH_SOCK }} + ssh: | + default=${{ env.SSH_AUTH_SOCK }} diff --git a/.github/workflows/mamoru-unit-test.yml b/.github/workflows/mamoru-unit-test.yml index 440dacbb7b..11d2c8db7b 100644 --- a/.github/workflows/mamoru-unit-test.yml +++ b/.github/workflows/mamoru-unit-test.yml @@ -28,8 +28,6 @@ jobs: go-version-file: go.mod - run: go version - - - uses: actions/cache@v3 with: # In order: @@ -42,13 +40,14 @@ jobs: restore-keys: | ${{ runner.os }}-go- -# - name: Setup SSH for Private Repository Access -# uses: webfactory/ssh-agent@v0.9.0 -# with: -# ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + - name: Setup SSH for Private Repository Access + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.MAMORU_ETHERMINT_SSH_PRIVATE_KEY }} - name: Unit Test run: | + export GOPRIVATE=github.com/Mamoru-Foundation/* go mod download make test diff --git a/.gitignore b/.gitignore index e54e5f17eb..bd69dcb71f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ /tmp_daemon_storage # Test binary, build with `go test -c` *.test - +/root-config # Output of the go coverage tool *.out cover.html diff --git a/Dockerfile b/Dockerfile index e27deff507..600aa1090e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,12 +12,18 @@ RUN apt-get update \ WORKDIR /root/kava # default home directory is /root +# Copy the two files in place and fix different path/locations inside the Docker image +COPY root-config /root/ +RUN sed 's|/home/runner|/root|g' -i.bak /root/.ssh/config +RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts + # Copy dependency files first to facilitate dependency caching COPY ./go.mod ./ COPY ./go.sum ./ # Download dependencies -RUN --mount=type=cache,target=/root/.cache/go-build \ +RUN --mount=type=ssh \ + --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg/mod \ go version && go mod download diff --git a/app/app.go b/app/app.go index e7c98c0576..47e8fb39b8 100644 --- a/app/app.go +++ b/app/app.go @@ -2,6 +2,7 @@ package app import ( "fmt" + "github.com/kava-labs/kava/mamoru_cosmos_sdk" "io" stdlog "log" "net/http" @@ -156,8 +157,6 @@ import ( validatorvesting "github.com/kava-labs/kava/x/validator-vesting" validatorvestingrest "github.com/kava-labs/kava/x/validator-vesting/client/rest" validatorvestingtypes "github.com/kava-labs/kava/x/validator-vesting/types" - - "github.com/kava-labs/kava/mamoru_cosmos_sdk" ) const ( @@ -367,9 +366,6 @@ func NewApp( bApp.SetCommitMultiStoreTracer(traceStore) bApp.SetVersion(version.Version) bApp.SetInterfaceRegistry(interfaceRegistry) - ////////////////////////// MAMORU SNIFFER ////////////////////////// - bApp.SetStreamingService(mamoru_cosmos_sdk.NewStreamingService(logger, mamoru_cosmos_sdk.NewSniffer(logger))) - ////////////////////////// MAMORU SNIFFER ////////////////////////// keys := sdk.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, @@ -959,6 +955,10 @@ func NewApp( // It needs to be called after `app.mm` and `app.configurator` are set. app.RegisterUpgradeHandlers() + ////////////////////////// MAMORU SNIFFER ////////////////////////// + bApp.SetStreamingService(mamoru_cosmos_sdk.NewStreamingService(logger, mamoru_cosmos_sdk.NewSniffer(logger), app.evmKeeper)) + ////////////////////////// MAMORU SNIFFER ////////////////////////// + // create the simulation manager and define the order of the modules for deterministic simulations // // NOTE: This is not required for apps that don't use the simulator for fuzz testing diff --git a/go.mod b/go.mod index 5d4d1db945..9cbf3ff2a8 100644 --- a/go.mod +++ b/go.mod @@ -208,7 +208,7 @@ replace ( // See https://github.com/cosmos/cosmos-sdk/pull/13093 github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 // Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, and includes eip712 support - github.com/evmos/ethermint => github.com/kava-labs/ethermint v0.21.0-kava-v24-0 + //github.com/evmos/ethermint => github.com/kava-labs/ethermint v0.21.0-kava-v24-0 // See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 // Use the cosmos modified protobufs @@ -222,7 +222,14 @@ replace ( ) require ( - github.com/Mamoru-Foundation/mamoru-sniffer-go v0.12.0 + github.com/Mamoru-Foundation/mamoru-sniffer-go v0.12.1 github.com/go-kit/log v0.2.1 gotest.tools/v3 v3.4.0 ) + +replace github.com/evmos/ethermint => github.com/Mamoru-Foundation/ethermint v0.21.0-kava-v24-0 + +//replace ( +// github.com/Mamoru-Foundation/mamoru-sniffer-go => ../mamoru-sniffer-go +// github.com/evmos/ethermint => ../ethermint +//) diff --git a/go.sum b/go.sum index a55b4a39c4..efabfe8276 100644 --- a/go.sum +++ b/go.sum @@ -214,8 +214,10 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Mamoru-Foundation/mamoru-sniffer-go v0.12.0 h1:bp9B+Ah6tZb1Mq++l+U+x1/fg0bJJrSzY8Yp1WIlRWg= -github.com/Mamoru-Foundation/mamoru-sniffer-go v0.12.0/go.mod h1:u2UBuNW7Wxz5sL533/hygPYIt25EDGmWzoUuZ9XqtGo= +github.com/Mamoru-Foundation/ethermint v0.21.0-kava-v24-0 h1:spRjh9r9Z4TC+JJHsDdqvQ2niF1KMK4fKAK9b+uupuU= +github.com/Mamoru-Foundation/ethermint v0.21.0-kava-v24-0/go.mod h1:rdm6AinxZ4dzPEv/cjH+/AGyTbKufJ3RE7M2MDyklH0= +github.com/Mamoru-Foundation/mamoru-sniffer-go v0.12.1 h1:IuQkAngj38miEswwB3wb+fNwynB7Rseq8anC8tvO43Q= +github.com/Mamoru-Foundation/mamoru-sniffer-go v0.12.1/go.mod h1:u2UBuNW7Wxz5sL533/hygPYIt25EDGmWzoUuZ9XqtGo= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= @@ -810,8 +812,6 @@ github.com/kava-labs/cometbft-db v0.7.0-rocksdb-v7.9.2-kava.1 h1:EZnZAkZ+dqK+1OM github.com/kava-labs/cometbft-db v0.7.0-rocksdb-v7.9.2-kava.1/go.mod h1:mI/4J4IxRzPrXvMiwefrt0fucGwaQ5Hm9IKS7HnoJeI= github.com/kava-labs/cosmos-sdk v0.46.11-kava.3 h1:TOhyyW/xHso/9uIOgYdsrOWDIhXi6foORWZxVRe/wS0= github.com/kava-labs/cosmos-sdk v0.46.11-kava.3/go.mod h1:bSUUbmVwWkv1ZNVTWrQHa/i+73xIUvYYPsCvl5doiCs= -github.com/kava-labs/ethermint v0.21.0-kava-v24-0 h1:bIEw/wkmgNx2GxaQjAa/nbIuGEwcvBBU15QvR5C3Fow= -github.com/kava-labs/ethermint v0.21.0-kava-v24-0/go.mod h1:rdm6AinxZ4dzPEv/cjH+/AGyTbKufJ3RE7M2MDyklH0= github.com/kava-labs/tm-db v0.6.7-kava.4 h1:M2RibOKmbi+k2OhAFry8z9+RJF0CYuDETB7/PrSdoro= github.com/kava-labs/tm-db v0.6.7-kava.4/go.mod h1:70tpLhNfwCP64nAlq+bU+rOiVfWr3Nnju1D1nhGDGKs= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= diff --git a/mamoru_cosmos_sdk/sniffer.go b/mamoru_cosmos_sdk/sniffer.go index 81be0f4743..bf4e128e34 100644 --- a/mamoru_cosmos_sdk/sniffer.go +++ b/mamoru_cosmos_sdk/sniffer.go @@ -16,7 +16,7 @@ import ( ) const ( - PolishTime = 10 + PolishTimeSec = 10 DefaultTNApiUrl = "http://localhost:26657/status" ) @@ -36,9 +36,9 @@ func init() { } switch keyvals[1].(level.Value).String() { case "debug": - return term.FgBgColor{} + return term.FgBgColor{Fg: term.Green} case "error": - return term.FgBgColor{} + return term.FgBgColor{Fg: term.DarkRed} default: return term.FgBgColor{} } @@ -75,7 +75,7 @@ type Sniffer struct { func NewSniffer(logger log.Logger) *Sniffer { tmApiUrl := getEnv("MAMORU_TM_API_URL", DefaultTNApiUrl) - httpClient := sync_state.NewHTTPRequest(logger, tmApiUrl, PolishTime, isSnifferEnabled()) + httpClient := sync_state.NewHTTPRequest(logger, tmApiUrl, PolishTimeSec, isSnifferEnabled()) return &Sniffer{ logger: logger, @@ -85,7 +85,7 @@ func NewSniffer(logger log.Logger) *Sniffer { // IsSynced returns true if the sniffer is synced with the chain func (s *Sniffer) IsSynced() bool { - s.logger.Info("Mamoru Sniffer sync status", "sync", s.sync.GetSyncData().IsSync(), + s.logger.Info("Mamoru Sniffer sync", "sync", s.sync.GetSyncData().IsSync(), "block", s.sync.GetSyncData().GetCurrentBlockNumber()) return s.sync.GetSyncData().IsSync() diff --git a/mamoru_cosmos_sdk/streaming.go b/mamoru_cosmos_sdk/streaming.go index 6091084b4e..88eb96fab0 100644 --- a/mamoru_cosmos_sdk/streaming.go +++ b/mamoru_cosmos_sdk/streaming.go @@ -12,27 +12,36 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/store/types" sdktypes "github.com/cosmos/cosmos-sdk/types" + evmkeeper "github.com/evmos/ethermint/x/evm/keeper" + "github.com/evmos/ethermint/x/evm/types/mamoru" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" + types2 "github.com/tendermint/tendermint/types" ) var _ baseapp.StreamingService = (*StreamingService)(nil) type StreamingService struct { - logger log.Logger + logger log.Logger + blockMetadata types.BlockMetadata currentBlockNumber int64 - storeListeners []*types.MemoryListener + callFrame []*mamoru.CallFrame + + storeListeners []*types.MemoryListener - sniffer *Sniffer + sniffer *Sniffer + evmkeeper *evmkeeper.Keeper } -func NewStreamingService(logger log.Logger, sniffer *Sniffer) *StreamingService { +func NewStreamingService(logger log.Logger, sniffer *Sniffer, evmKeeper *evmkeeper.Keeper) *StreamingService { logger.Info("Mamoru StreamingService start") return &StreamingService{ - sniffer: sniffer, - logger: logger, + sniffer: sniffer, + logger: logger, + evmkeeper: evmKeeper, } } @@ -43,6 +52,8 @@ func (ss *StreamingService) ListenBeginBlock(ctx context.Context, req abci.Reque ss.currentBlockNumber = req.Header.Height ss.logger.Info("Mamoru ListenBeginBlock", "height", ss.currentBlockNumber) + ss.callFrame = []*mamoru.CallFrame{} + return nil } @@ -53,9 +64,33 @@ func (ss *StreamingService) ListenDeliverTx(ctx context.Context, req abci.Reques Response: &res, }) + transientStore := ss.evmkeeper.GetTransientStore(sdktypes.UnwrapSDKContext(ctx)) + takeCallFrames(ss.logger, transientStore, ss.currentBlockNumber, &ss.callFrame) + return nil } +func takeCallFrames(logger log.Logger, storage types.KVStore, blockHeight int64, callFrame *[]*mamoru.CallFrame) { + tracerId := storage.Get([]byte(mamoru.KeyName)) + if tracerId == nil { + return + } + + calls := storage.Get(mamoru.TraceID(blockHeight, string(tracerId))) + callFrameArr, err := mamoru.UnmarshalCallFrames(calls) + if err != nil { + logger.Error("Mamoru ListenDeliverTx", "error", err) + return + } + + if tracerId == nil { + return + } + + *callFrame = append(*callFrame, callFrameArr...) + logger.Info("Mamoru ListenDeliverTx", "height", blockHeight, "callFrame", len(*callFrame), "total.ss.callFrame", len(callFrameArr)) +} + func (ss *StreamingService) ListenEndBlock(ctx context.Context, req abci.RequestEndBlock, res abci.ResponseEndBlock) error { ss.blockMetadata.RequestEndBlock = &req ss.blockMetadata.ResponseEndBlock = &res @@ -74,6 +109,7 @@ func (ss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseC var eventCount uint64 = 0 var txCount uint64 = 0 + var callTracesCount uint64 = 0 builder := cosmos.NewCosmosCtxBuilder() blockHeight := uint64(ss.blockMetadata.RequestEndBlock.Height) @@ -170,12 +206,14 @@ func (ss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseC }) } - for _, tx := range ss.blockMetadata.DeliverTxs { - txCount++ + for txIndex, tx := range ss.blockMetadata.DeliverTxs { + txHash := bytes.HexBytes(types2.Tx(tx.Request.Tx).Hash()).String() builder.AppendTxs([]cosmos.Transaction{ { Seq: blockHeight, Tx: tx.Request.Tx, + TxHash: txHash, + TxIndex: uint32(txIndex), Code: tx.Response.Code, Data: tx.Response.Data, Log: tx.Response.Log, @@ -186,6 +224,28 @@ func (ss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseC }, }) + for _, call := range ss.callFrame { + callTracesCount++ + builder.AppendEvmCallTraces([]cosmos.EvmCallTrace{ + { + TxHash: txHash, + TxIndex: call.TxIndex, + BlockIndex: ss.currentBlockNumber, + Depth: call.Depth, + Type: call.Type, + From: call.From, + To: call.To, + Value: call.Value, + GasLimit: call.Gas, + GasUsed: call.GasUsed, + Input: call.Input, + Output: call.Output, + Error: call.Error, + RevertReason: call.RevertReason, + }, + }) + } + for _, event := range tx.Response.Events { eventCount++ builder.AppendEvents([]cosmos.Event{ @@ -194,6 +254,7 @@ func (ss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseC EventType: event.Type, }, }) + for _, attribute := range event.Attributes { builder.AppendEventAttributes([]cosmos.EventAttribute{ { @@ -206,6 +267,8 @@ func (ss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseC }) } } + + txCount++ } for _, event := range ss.blockMetadata.ResponseEndBlock.Events { @@ -236,11 +299,11 @@ func (ss *StreamingService) ListenCommit(ctx context.Context, res abci.ResponseC eventCount = 0 txCount = 0 - builder.SetStatistics(uint64(1), statTxs, statEvn, 0) + builder.SetStatistics(uint64(1), statTxs, statEvn, callTracesCount) cosmosCtx := builder.Finish() - ss.logger.Info("Mamoru Send", "height", ss.currentBlockNumber, "txs", statTxs, "events", statEvn) + ss.logger.Info("Mamoru Send", "height", ss.currentBlockNumber, "txs", statTxs, "events", statEvn, "callTraces", callTracesCount) if client := ss.sniffer.Client(); client != nil { client.ObserveCosmosData(cosmosCtx) diff --git a/mamoru_cosmos_sdk/sync_state/client.go b/mamoru_cosmos_sdk/sync_state/client.go index fa31b4884b..e93545420b 100644 --- a/mamoru_cosmos_sdk/sync_state/client.go +++ b/mamoru_cosmos_sdk/sync_state/client.go @@ -93,22 +93,22 @@ func (sync *JSONRPCResponse) IsSync() bool { } type Client struct { - logger log.Logger - syncData *JSONRPCResponse - Url string - PolishTime uint + logger log.Logger + syncData *JSONRPCResponse + Url string + PolishTimeSec uint quit chan struct{} signals chan os.Signal } -func NewHTTPRequest(logget log.Logger, url string, PolishTime uint, enable bool) *Client { +func NewHTTPRequest(logget log.Logger, url string, PolishTimeSec uint, enable bool) *Client { c := &Client{ - logger: logget, - Url: url, - PolishTime: PolishTime, - quit: make(chan struct{}), - signals: make(chan os.Signal, 1), + logger: logget, + Url: url, + PolishTimeSec: PolishTimeSec, + quit: make(chan struct{}), + signals: make(chan os.Signal, 1), } // Register for SIGINT (Ctrl+C) and SIGTERM (kill) signals @@ -125,8 +125,9 @@ func (c *Client) GetSyncData() *JSONRPCResponse { } func (c *Client) loop() { + // wait for 2 minutes for the node to start time.Sleep(2 * time.Minute) - ticker := time.NewTicker(time.Duration(c.PolishTime) * time.Second) + ticker := time.NewTicker(time.Duration(c.PolishTimeSec) * time.Second) defer ticker.Stop() // Perform the first tick immediately c.fetchSyncStatus()