From ecfaa9cef187a681c9e6d0222128c304bd7ec438 Mon Sep 17 00:00:00 2001 From: Sean Zheng Date: Sun, 28 Jul 2024 15:19:24 +0800 Subject: [PATCH 1/2] feat: integrate Tonx package and client into project - Add `tonx` package to wire.go and wire_gen.go - Add `initTonx` function to wire.go and wire_gen.go - Modify `NewBlockService` function in block_service.go to accept `tonx.Client` as input Signed-off-by: Sean Zheng --- adapter/block/scan/wire.go | 6 ++++++ adapter/block/scan/wire_gen.go | 11 ++++++++++- app/domain/block/biz/block_service.go | 8 ++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/adapter/block/scan/wire.go b/adapter/block/scan/wire.go index b38277c..ebc3cf0 100644 --- a/adapter/block/scan/wire.go +++ b/adapter/block/scan/wire.go @@ -12,6 +12,7 @@ import ( "github.com/blackhorseya/ryze/app/domain/block/biz" "github.com/blackhorseya/ryze/app/infra/configx" "github.com/blackhorseya/ryze/app/infra/otelx" + "github.com/blackhorseya/ryze/app/infra/tonx" "github.com/blackhorseya/ryze/app/infra/transports/httpx" "github.com/blackhorseya/ryze/pkg/adapterx" "github.com/blackhorseya/ryze/pkg/contextx" @@ -37,6 +38,10 @@ func initServer(app *configx.Application) (*httpx.Server, error) { return httpx.NewServer(app.HTTP) } +func initTonx() (*tonx.Client, error) { + return tonx.NewClient(tonx.Options{Network: "mainnet"}) +} + func New(v *viper.Viper) (adapterx.Restful, error) { panic(wire.Build( wire.Struct(new(wirex.Injector), "*"), @@ -47,5 +52,6 @@ func New(v *viper.Viper) (adapterx.Restful, error) { initServer, biz.NewBlockService, + initTonx, )) } diff --git a/adapter/block/scan/wire_gen.go b/adapter/block/scan/wire_gen.go index 1d13046..84a9c33 100644 --- a/adapter/block/scan/wire_gen.go +++ b/adapter/block/scan/wire_gen.go @@ -13,6 +13,7 @@ import ( "github.com/blackhorseya/ryze/app/domain/block/biz" "github.com/blackhorseya/ryze/app/infra/configx" "github.com/blackhorseya/ryze/app/infra/otelx" + "github.com/blackhorseya/ryze/app/infra/tonx" "github.com/blackhorseya/ryze/app/infra/transports/httpx" "github.com/blackhorseya/ryze/pkg/adapterx" "github.com/blackhorseya/ryze/pkg/contextx" @@ -34,7 +35,11 @@ func New(v *viper.Viper) (adapterx.Restful, error) { if err != nil { return nil, err } - blockServiceServer := biz.NewBlockService() + client, err := initTonx() + if err != nil { + return nil, err + } + blockServiceServer := biz.NewBlockService(client) injector := &wirex.Injector{ C: configuration, A: application, @@ -67,3 +72,7 @@ func initApplication(config *configx.Configuration) (*configx.Application, error func initServer(app *configx.Application) (*httpx.Server, error) { return httpx.NewServer(app.HTTP) } + +func initTonx() (*tonx.Client, error) { + return tonx.NewClient(tonx.Options{Network: "mainnet"}) +} diff --git a/app/domain/block/biz/block_service.go b/app/domain/block/biz/block_service.go index 856b315..e13edc3 100644 --- a/app/domain/block/biz/block_service.go +++ b/app/domain/block/biz/block_service.go @@ -3,16 +3,20 @@ package biz import ( "context" + "github.com/blackhorseya/ryze/app/infra/tonx" "github.com/blackhorseya/ryze/entity/domain/block/model" "google.golang.org/protobuf/types/known/timestamppb" ) type impl struct { + client *tonx.Client } // NewBlockService is used to create a new model.BlockServiceServer -func NewBlockService() model.BlockServiceServer { - return &impl{} +func NewBlockService(client *tonx.Client) model.BlockServiceServer { + return &impl{ + client: client, + } } func (i *impl) GetBlock(ctx context.Context, request *model.GetBlockRequest) (*model.Block, error) { From c5e2b4d275bc806a91239c8127929a05134508ac Mon Sep 17 00:00:00 2001 From: Sean Zheng Date: Sun, 28 Jul 2024 16:04:46 +0800 Subject: [PATCH 2/2] feat: update `ScanBlock` function with new API calls - Add new imports for `ton` and `zap` packages - Refactor `ScanBlock` function to use new API calls and error handling - Add unit tests for the `ScanBlock` function Signed-off-by: Sean Zheng --- app/domain/block/biz/block_service.go | 40 ++++++++++++++++++-- app/domain/block/biz/block_service_test.go | 44 ++++++++++++++++++++++ app/infra/tonx/utils.go | 12 ++++++ 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 app/domain/block/biz/block_service_test.go create mode 100644 app/infra/tonx/utils.go diff --git a/app/domain/block/biz/block_service.go b/app/domain/block/biz/block_service.go index e13edc3..51e3603 100644 --- a/app/domain/block/biz/block_service.go +++ b/app/domain/block/biz/block_service.go @@ -5,6 +5,9 @@ import ( "github.com/blackhorseya/ryze/app/infra/tonx" "github.com/blackhorseya/ryze/entity/domain/block/model" + "github.com/blackhorseya/ryze/pkg/contextx" + "github.com/xssnick/tonutils-go/ton" + "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -34,7 +37,38 @@ func (i *impl) GetBlocks(request *model.GetBlocksRequest, server model.BlockServ panic("implement me") } -func (i *impl) ScanBlock(request *model.ScanBlockRequest, server model.BlockService_ScanBlockServer) error { - // TODO: 2024/7/28|sean|implement me - panic("implement me") +func (i *impl) ScanBlock(request *model.ScanBlockRequest, stream model.BlockService_ScanBlockServer) error { + api := ton.NewAPIClient(i.client, ton.ProofCheckPolicyFast).WithRetry() + api.SetTrustedBlockFromConfig(i.client.Config) + + ctx := contextx.WithContext(stream.Context()) + master, err := api.GetMasterchainInfo(ctx) + if err != nil { + ctx.Error("failed to get masterchain info", zap.Error(err)) + return err + } + ctx.Info("master proofs chain successfully verified, all data is now safe and trusted!") + + stickyContext := api.Client().StickyContext(ctx) + shardLastSeqno := map[string]uint32{} + firstShards, err := api.GetBlockShardsInfo(stickyContext, master) + if err != nil { + ctx.Error("failed to get block shards info", zap.Error(err)) + return err + } + + for _, shard := range firstShards { + shardLastSeqno[tonx.GetShardID(shard)] = shard.SeqNo + } + + for { + ctx.Info("scanning master block", zap.Uint32("seq_no", master.SeqNo)) + + next := master.SeqNo + 1 + master, err = api.WaitForBlock(next).LookupBlock(ctx, master.Workchain, master.Shard, next) + if err != nil { + ctx.Error("failed to lookup block", zap.Uint32("seq_no", next), zap.Error(err)) + return err + } + } } diff --git a/app/domain/block/biz/block_service_test.go b/app/domain/block/biz/block_service_test.go new file mode 100644 index 0000000..888890d --- /dev/null +++ b/app/domain/block/biz/block_service_test.go @@ -0,0 +1,44 @@ +package biz + +import ( + "testing" + "time" + + "github.com/blackhorseya/ryze/app/infra/tonx" + "github.com/blackhorseya/ryze/entity/domain/block/model" + "github.com/blackhorseya/ryze/pkg/contextx" + "github.com/stretchr/testify/suite" + "go.uber.org/mock/gomock" +) + +type suiteTester struct { + suite.Suite + + ctrl *gomock.Controller + client *tonx.Client + biz model.BlockServiceServer +} + +func (s *suiteTester) SetupTest() { + s.ctrl = gomock.NewController(s.T()) + s.client, _ = tonx.NewClient(tonx.Options{Network: "testnet"}) + s.biz = NewBlockService(s.client) +} + +func (s *suiteTester) TearDownTest() { + s.ctrl.Finish() +} + +func TestAll(t *testing.T) { + suite.Run(t, new(suiteTester)) +} + +func (s *suiteTester) Test_impl_ScanBlock() { + stream := model.NewMockBlockService_ScanBlockServer(s.ctrl) + + timeout, cancelFunc := contextx.WithTimeout(contextx.Background(), 2*time.Second) + defer cancelFunc() + + stream.EXPECT().Context().Return(timeout).Times(1) + _ = s.biz.ScanBlock(&model.ScanBlockRequest{}, stream) +} diff --git a/app/infra/tonx/utils.go b/app/infra/tonx/utils.go new file mode 100644 index 0000000..d11ed53 --- /dev/null +++ b/app/infra/tonx/utils.go @@ -0,0 +1,12 @@ +package tonx + +import ( + "fmt" + + "github.com/xssnick/tonutils-go/ton" +) + +// GetShardID is used to get the shard id +func GetShardID(shard *ton.BlockIDExt) string { + return fmt.Sprintf("%d|%d", shard.Workchain, shard.Shard) +}