Squashed commit of the following:

commit 05d142664d
Author: Mohamed Sohail 天明 <sohailsameja@gmail.com>
Date:   Mon Oct 7 15:12:58 2024 +0300

    feat: handle contract creation (#43)

    * feat: add contract creation handler

    * fix: process contract creations

    * fix: redis keys name

commit 4b2ad3daf9
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon Oct 7 15:12:15 2024 +0300

    build(deps): bump github.com/knadh/koanf/providers/env (#37)

    Bumps [github.com/knadh/koanf/providers/env](https://github.com/knadh/koanf) from 0.1.0 to 1.0.0.
    - [Release notes](https://github.com/knadh/koanf/releases)
    - [Commits](https://github.com/knadh/koanf/compare/v0.1.0...v1.0.0)

    ---
    updated-dependencies:
    - dependency-name: github.com/knadh/koanf/providers/env
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit f1086fcdc1
Author: Mohamed Sohail 天明 <sohailsameja@gmail.com>
Date:   Mon Oct 7 10:07:11 2024 +0300

    feat: optimize exists to check multiple keys in one call (#40)

    * closes #32

commit fd59d286f5
Author: Mohammed Sohail <sohailsameja@gmail.com>
Date:   Mon Oct 7 09:49:01 2024 +0300

    feat: add custodial registration proxy handler
This commit is contained in:
2024-10-07 15:14:24 +03:00
parent 8e3e027044
commit 725c18c0ff
12 changed files with 206 additions and 30 deletions

View File

@@ -9,7 +9,7 @@ type (
Cache interface {
Add(context.Context, string) error
Remove(context.Context, string) error
Exists(context.Context, string) (bool, error)
Exists(context.Context, ...string) (bool, error)
Size(context.Context) (int64, error)
}

View File

@@ -40,8 +40,8 @@ func (c *redisCache) Remove(ctx context.Context, key string) error {
return c.client.Do(ctx, cmd).Error()
}
func (c *redisCache) Exists(ctx context.Context, key string) (bool, error) {
cmd := c.client.B().Exists().Key(key).Build()
func (c *redisCache) Exists(ctx context.Context, keys ...string) (bool, error) {
cmd := c.client.B().Exists().Key(keys...).Build()
res, err := c.client.Do(ctx, cmd).AsBool()
if err != nil {
return false, err

View File

@@ -26,9 +26,14 @@ func (c *mapCache) Remove(_ context.Context, key string) error {
return nil
}
func (c *mapCache) Exists(_ context.Context, key string) (bool, error) {
_, ok := c.xmap.Load(key)
return ok, nil
func (c *mapCache) Exists(_ context.Context, key ...string) (bool, error) {
for _, v := range key {
_, ok := c.xmap.Load(v)
if ok {
return true, nil
}
}
return false, nil
}
func (c *mapCache) Size(_ context.Context) (int64, error) {

View File

@@ -0,0 +1,28 @@
package handler
import (
"context"
"github.com/grassrootseconomics/eth-tracker/pkg/event"
"github.com/grassrootseconomics/eth-tracker/pkg/router"
)
const contractCreationEventName = "CONTRACT_CREATION"
func HandleContractCreation() router.ContractCreationHandlerFunc {
return func(ctx context.Context, ccp router.ContractCreationPayload, c router.Callback) error {
contractCreationEvent := event.Event{
Block: ccp.Block,
ContractAddress: ccp.ContractAddress,
Success: ccp.Success,
Timestamp: ccp.Timestamp,
TxHash: ccp.TxHash,
TxType: contractCreationEventName,
Payload: map[string]any{
"from": ccp.From,
},
}
return c(ctx, contractCreationEvent)
}
}

View File

@@ -0,0 +1,66 @@
package handler
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/grassrootseconomics/eth-tracker/pkg/event"
"github.com/grassrootseconomics/eth-tracker/pkg/router"
"github.com/lmittmann/w3"
)
const custodialRegistrationEventName = "CUSTODIAL_REGISTRATION"
var (
custodialRegistrationEvent = w3.MustNewEvent("NewRegistration(address indexed subject)")
custodialRegistrationSig = w3.MustNewFunc("register(address)", "")
)
func HandleCustodialRegistrationLog() router.LogHandlerFunc {
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
var account common.Address
if err := custodialRegistrationEvent.DecodeArgs(lp.Log, &account); err != nil {
return err
}
custodialRegistrationEvent := event.Event{
Index: lp.Log.Index,
Block: lp.Log.BlockNumber,
ContractAddress: lp.Log.Address.Hex(),
Success: true,
Timestamp: lp.Timestamp,
TxHash: lp.Log.TxHash.Hex(),
TxType: custodialRegistrationEventName,
Payload: map[string]any{
"account": account.Hex(),
},
}
return c(ctx, custodialRegistrationEvent)
}
}
func HandleCustodialRegistrationInputData() router.InputDataHandlerFunc {
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
var account common.Address
if err := custodialRegistrationSig.DecodeArgs(w3.B(idp.InputData), &account); err != nil {
return err
}
custodialRegistrationEvent := event.Event{
Block: idp.Block,
ContractAddress: idp.ContractAddress,
Success: false,
Timestamp: idp.Timestamp,
TxHash: idp.TxHash,
TxType: custodialRegistrationEventName,
Payload: map[string]any{
"account": account.Hex(),
},
}
return c(ctx, custodialRegistrationEvent)
}
}

View File

@@ -147,16 +147,10 @@ func (hc *HandlerContainer) checkStables(ctx context.Context, from string, to st
return true, nil
}
// TODO: Pipeline this check on Redis with a new method
fromExists, err := hc.cache.Exists(ctx, from)
exists, err := hc.cache.Exists(ctx, from, to)
if err != nil {
return false, err
}
toExists, err := hc.cache.Exists(ctx, to)
if err != nil {
return false, err
}
return fromExists || toExists, nil
return exists, nil
}

View File

@@ -54,7 +54,7 @@ func (p *Processor) ProcessBlock(ctx context.Context, blockNumber uint64) error
}
for _, receipt := range receipts {
if receipt.Status > 0 {
if receipt.Status == 1 {
for _, log := range receipt.Logs {
exists, err := p.cache.Exists(ctx, log.Address.Hex())
if err != nil {
@@ -72,13 +72,72 @@ func (p *Processor) ProcessBlock(ctx context.Context, blockNumber uint64) error
}
}
}
} else {
if receipt.ContractAddress != (common.Address{}) {
tx, err := p.chain.GetTransaction(ctx, receipt.TxHash)
if err != nil && !errors.Is(err, context.Canceled) {
return fmt.Errorf("get transaction error: tx %s: %v", receipt.TxHash.Hex(), err)
}
from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
if err != nil {
return fmt.Errorf("transaction decode error: tx %s: %v", receipt.TxHash.Hex(), err)
}
exists, err := p.cache.Exists(ctx, from.Hex())
if err != nil {
return err
}
if exists {
if err := p.router.ProcessContractCreation(
ctx,
router.ContractCreationPayload{
From: from.Hex(),
Block: blockNumber,
ContractAddress: receipt.ContractAddress.Hex(),
Timestamp: block.Time(),
TxHash: receipt.TxHash.Hex(),
Success: true,
},
); err != nil && !errors.Is(err, context.Canceled) {
return fmt.Errorf("route success contract creation error: tx %s: %v", receipt.TxHash.Hex(), err)
}
}
}
}
if receipt.Status == 0 {
tx, err := p.chain.GetTransaction(ctx, receipt.TxHash)
if err != nil && !errors.Is(err, context.Canceled) {
return fmt.Errorf("get transaction error: tx %s: %v", receipt.TxHash.Hex(), err)
}
if tx.To() == nil {
from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
if err != nil {
return fmt.Errorf("transaction decode error: tx %s: %v", receipt.TxHash.Hex(), err)
}
if tx.To() != nil {
exists, err := p.cache.Exists(ctx, from.Hex())
if err != nil {
return err
}
if exists {
if err := p.router.ProcessContractCreation(
ctx,
router.ContractCreationPayload{
From: from.Hex(),
Block: blockNumber,
ContractAddress: receipt.ContractAddress.Hex(),
Timestamp: block.Time(),
TxHash: receipt.TxHash.Hex(),
Success: false,
},
); err != nil && !errors.Is(err, context.Canceled) {
return fmt.Errorf("route reverted contract creation error: tx %s: %v", receipt.TxHash.Hex(), err)
}
}
} else {
exists, err := p.cache.Exists(ctx, tx.To().Hex())
if err != nil {
return err