From 29a948c581d010d5321cba59bee50a1439cfeeff Mon Sep 17 00:00:00 2001 From: Konst Date: Mon, 23 Dec 2024 22:34:14 +0300 Subject: [PATCH] Added transactions converting --- pkg/indexer/indexer.go | 8 ++ pkg/indexer/subsquid/adapter/adapter.go | 4 +- pkg/indexer/subsquid/adapter/convert.go | 127 ++++++++++++++++++ pkg/indexer/subsquid/adapter/listen.go | 10 +- .../receiver/api/getDeployContractAddress.go | 15 +++ pkg/indexer/subsquid/receiver/api/response.go | 18 ++- 6 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 pkg/indexer/subsquid/adapter/convert.go create mode 100644 pkg/indexer/subsquid/receiver/api/getDeployContractAddress.go diff --git a/pkg/indexer/indexer.go b/pkg/indexer/indexer.go index 397abba..1b0107d 100644 --- a/pkg/indexer/indexer.go +++ b/pkg/indexer/indexer.go @@ -3,6 +3,7 @@ package indexer import ( "bytes" "context" + sqdAdapter "github.com/dipdup-io/starknet-indexer/pkg/indexer/subsquid/adapter" sqdRcvr "github.com/dipdup-io/starknet-indexer/pkg/indexer/subsquid/receiver" "runtime" "sync" @@ -55,6 +56,7 @@ type Indexer struct { idGenerator *generator.IdGenerator receiver *receiver.Receiver sqdReceiver *sqdRcvr.Receiver + adapter *sqdAdapter.Adapter statusChecker *statusChecker rollbackManager models.Rollback @@ -111,6 +113,11 @@ func New( return nil, err } indexer.sqdReceiver = sqdReceiver + indexer.adapter = sqdAdapter.New() + + if err = indexer.adapter.AttachTo(indexer.sqdReceiver, sqdRcvr.OutputName, sqdAdapter.InputName); err != nil { + return nil, errors.Wrap(err, "while attaching adapter to receiver") + } default: rcvr, err := receiver.NewReceiver(cfg, datasource) if err != nil { @@ -157,6 +164,7 @@ func (indexer *Indexer) Start(ctx context.Context) { switch indexer.cfg.Datasource { case "subsquid": indexer.sqdReceiver.Start(ctx) + indexer.adapter.Start(ctx) default: indexer.receiver.Start(ctx) indexer.G.GoCtx(ctx, indexer.sync) diff --git a/pkg/indexer/subsquid/adapter/adapter.go b/pkg/indexer/subsquid/adapter/adapter.go index 0910c7c..347e104 100644 --- a/pkg/indexer/subsquid/adapter/adapter.go +++ b/pkg/indexer/subsquid/adapter/adapter.go @@ -17,8 +17,8 @@ const ( StopOutput = "stop" ) -func New() Adapter { - m := Adapter{ +func New() *Adapter { + m := &Adapter{ BaseModule: modules.New("sqd adapter"), } m.CreateInputWithCapacity(InputName, 128) diff --git a/pkg/indexer/subsquid/adapter/convert.go b/pkg/indexer/subsquid/adapter/convert.go new file mode 100644 index 0000000..d5d3f9f --- /dev/null +++ b/pkg/indexer/subsquid/adapter/convert.go @@ -0,0 +1,127 @@ +package adapter + +import ( + "context" + "fmt" + "github.com/dipdup-io/starknet-go-api/pkg/data" + "github.com/dipdup-io/starknet-go-api/pkg/encoding" + "github.com/dipdup-io/starknet-indexer/internal/storage" + "github.com/dipdup-io/starknet-indexer/pkg/indexer/receiver" + "github.com/dipdup-io/starknet-indexer/pkg/indexer/subsquid/receiver/api" + "time" +) + +func (a *Adapter) convert(_ context.Context, block *api.SqdBlockResponse) error { + fmt.Print("converting block number ") + fmt.Print(block.Header.Number) + fmt.Print("\n") + + b := receiver.Block{ + Height: block.Header.Number, + Status: storage.NewStatus(block.Header.Status), + Hash: data.Felt(block.Header.Hash).Bytes(), + ParentHash: data.Felt(block.Header.ParentHash).Bytes(), + NewRoot: encoding.MustDecodeHex(block.Header.NewRoot), + Time: time.Unix(block.Header.Timestamp, 0).UTC(), + SequencerAddress: encoding.MustDecodeHex(block.Header.SequencerAddress), + Transactions: convertTransactions(block), + Receipts: nil, + } + fmt.Print(b.Hash) + + return nil +} + +func convertTransactions(block *api.SqdBlockResponse) []receiver.Transaction { + txs := block.Transactions + resultTxs := make([]receiver.Transaction, len(txs)) + for i, tx := range txs { + var body any + switch tx.Type { + case data.TransactionTypeInvoke: + body = data.Invoke{ + MaxFee: stringToFelt(tx.MaxFee), + Nonce: uint64ToFelt(tx.Nonce), + ContractAddress: stringToFelt(tx.ContractAddress), + EntrypointSelector: stringToFelt(tx.EntryPointSelector), + SenderAddress: stringToFelt(tx.SenderAddress), + Signature: parseStringSlice(tx.Signature), + Calldata: parseStringSlice(tx.Calldata), + } + case data.TransactionTypeDeclare: + body = data.Declare{ + MaxFee: stringToFelt(tx.MaxFee), + Nonce: uint64ToFelt(tx.Nonce), + SenderAddress: stringToFelt(tx.SenderAddress), + ContractAddress: stringToFelt(tx.ContractAddress), + Signature: parseStringSlice(tx.Signature), + ClassHash: stringToFelt(tx.ClassHash), + CompiledClassHash: stringToFelt(tx.CompiledClassHash), + } + case data.TransactionTypeDeploy: + body = data.Deploy{ + ContractAddressSalt: parseString(tx.ContractAddressSalt), + ConstructorCalldata: parseStringSlice(tx.Calldata), + ClassHash: stringToFelt(tx.ClassHash), + ContractAddress: block.GetDeployContractAddress(tx.TransactionIndex), + } + case data.TransactionTypeDeployAccount: + body = data.DeployAccount{ + MaxFee: stringToFelt(tx.MaxFee), + Nonce: uint64ToFelt(tx.Nonce), + ContractAddress: stringToFelt(tx.ContractAddress), + ContractAddressSalt: parseString(tx.ContractAddressSalt), + ClassHash: stringToFelt(tx.ClassHash), + ConstructorCalldata: parseStringSlice(tx.ConstructorCalldata), + Signature: parseStringSlice(tx.Signature), + } + case data.TransactionTypeL1Handler: + body = data.L1Handler{ + Nonce: uint64ToFelt(tx.Nonce), + ContractAddress: stringToFelt(tx.ContractAddress), + EntrypointSelector: stringToFelt(tx.EntryPointSelector), + Calldata: parseStringSlice(tx.Calldata), + } + default: + return nil + } + + resultTxs[i] = receiver.Transaction{ + Type: tx.Type, + Version: data.Felt(tx.Version), + Hash: data.Felt(tx.TransactionHash), + Body: body, + } + } + + return resultTxs +} + +func uint64ToFelt(value *uint64) data.Felt { + if value == nil { + return "" + } + return data.Felt(fmt.Sprintf("%d", *value)) +} + +func stringToFelt(value *string) data.Felt { + if value == nil { + return "" + } + return data.Felt(*value) +} + +func parseStringSlice(value *[]string) []string { + if value == nil { + return []string{} + } + + return *value +} + +func parseString(value *string) string { + if value == nil { + return "" + } + return *value +} diff --git a/pkg/indexer/subsquid/adapter/listen.go b/pkg/indexer/subsquid/adapter/listen.go index 81f88bc..547662c 100644 --- a/pkg/indexer/subsquid/adapter/listen.go +++ b/pkg/indexer/subsquid/adapter/listen.go @@ -28,9 +28,13 @@ func (a *Adapter) listen(ctx context.Context) { continue } - a.Log.Info(). - Uint64("level", block.Header.Number). - Msg("received block") + if err := a.convert(ctx, block); err != nil { + a.Log.Err(err). + Uint64("height", block.Header.Number). + Msg("convert error") + a.MustOutput(StopOutput).Push(struct{}{}) + continue + } } } } diff --git a/pkg/indexer/subsquid/receiver/api/getDeployContractAddress.go b/pkg/indexer/subsquid/receiver/api/getDeployContractAddress.go new file mode 100644 index 0000000..23ee8ac --- /dev/null +++ b/pkg/indexer/subsquid/receiver/api/getDeployContractAddress.go @@ -0,0 +1,15 @@ +package api + +import "github.com/dipdup-io/starknet-go-api/pkg/data" + +func (block *SqdBlockResponse) GetDeployContractAddress(txIndex uint) data.Felt { + for _, trace := range block.Traces { + if trace.TraceType != data.TransactionTypeDeploy || trace.TraceType != data.TransactionTypeDeployAccount || + trace.TransactionIndex != txIndex { + continue + } + + return data.Felt(trace.ContractAddress) + } + return "" +} diff --git a/pkg/indexer/subsquid/receiver/api/response.go b/pkg/indexer/subsquid/receiver/api/response.go index 18262aa..c2bce0f 100644 --- a/pkg/indexer/subsquid/receiver/api/response.go +++ b/pkg/indexer/subsquid/receiver/api/response.go @@ -10,21 +10,25 @@ type SqdBlockResponse struct { } type BlockHeader struct { - Number uint64 `example:"321" json:"number"` - Hash string `example:"0x44529f2c44d9113e0ba4e53cb6e84f425ec186cda27545827b5a72d5540bfdc" json:"hash"` - Timestamp int64 `example:"1641950335" json:"timestamp"` + Number uint64 `example:"321" json:"number"` + Hash string `example:"0x44529f2c44d9113e0ba4e53cb6e84f425ec186cda27545827b5a72d5540bfdc" json:"hash"` + ParentHash string `example:"0x44529f2c44d9113e0ba4e53cb6e84f425ec186cda27545827b5a72d5540bfdc" json:"parentHash"` + Status string `example:"ACCEPTED_ON_L1" json:"status"` + NewRoot string `example:"0x44529f2c44d9113e0ba4e53cb6e84f425ec186cda27545827b5a72d5540bfdc" json:"newRoot"` + Timestamp int64 `example:"1641950335" json:"timestamp"` + SequencerAddress string `example:"0x44529f2c44d9113e0ba4e53cb6e84f425ec186cda27545827b5a72d5540bfdc" json:"sequencerAddress"` } type Transaction struct { - TransactionIndex uint `example:"0" json:"transactionIndex"` + TransactionIndex uint `example:"0" json:"transactionIndex"` TransactionHash string `example:"0x794fae89c8c4b8f5f77a4996948d2547740f90e54bb4a5cc6119a7c70eca42c" json:"transactionHash"` ContractAddress *string `example:"0x1cee8364383aea317eefc181dbd8732f1504fd4511aed58f32c369dd546da0d" json:"contractAddress"` EntryPointSelector *string `example:"0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f" json:"entryPointSelector"` Calldata *[]string `json:"calldata"` - MaxFee *string `example:"0x0" json:"maxFee"` - Type string `example:"INVOKE" json:"type"` + MaxFee *string `example:"0x0" json:"maxFee"` + Type string `example:"INVOKE" json:"type"` SenderAddress *string `json:"senderAddress"` - Version string `example:"0x0" json:"version"` + Version string `example:"0x0" json:"version"` Signature *[]string `json:"signature"` Nonce *uint64 `json:"nonce"` ClassHash *string `json:"classHash"`