diff --git a/indexer/types.go b/indexer/types.go index df93391..657dece 100644 --- a/indexer/types.go +++ b/indexer/types.go @@ -18,11 +18,12 @@ const ( ) type SearchKey struct { - Script *types.Script `json:"script"` - ScriptType types.ScriptType `json:"script_type"` - ScriptSearchMode types.ScriptSearchMode `json:"script_search_mode,omitempty"` - Filter *Filter `json:"filter,omitempty"` - WithData bool `json:"with_data"` + Script *types.Script `json:"script"` + ScriptType types.ScriptType `json:"script_type"` + ScriptSearchMode types.ScriptSearchMode `json:"script_search_mode,omitempty"` + Filter *Filter `json:"filter,omitempty"` + WithData bool `json:"with_data"` + GroupByTransaction *bool `json:"group_by_transaction,omitempty"` } type Filter struct { diff --git a/rpc/client.go b/rpc/client.go index affa7b9..08a4b82 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -172,14 +172,16 @@ type Client interface { RemoveTransaction(ctx context.Context, tx_hash types.Hash) (bool, error) - SendAlert(ctx context.Context, alert types.AlertMessage) error + SendAlert(ctx context.Context, alert types.Alert) error GetBlockTemplate(ctx context.Context) (types.BlockTemplate, error) TxPoolReady(ctx context.Context) (bool, error) // GetRawTxPool Returns all transaction ids in tx pool as a json array of string transaction ids. - GetRawTxPool(ctx context.Context, verbose *bool) (*types.RawTxPool, error) + GetRawTxPool(ctx context.Context) (*types.RawTxPool, error) + // GetRawTxPool Returns all transaction ids in tx pool as a json array of string transaction ids. + GetRawTxPoolVerbose(ctx context.Context) (*types.RawTxPoolVerbose, error) // ClearTxPool Removes all transactions from the transaction pool. ClearTxPool(ctx context.Context) error @@ -774,14 +776,21 @@ func (cli *client) TxPoolInfo(ctx context.Context) (*types.TxPoolInfo, error) { return &result, nil } -func (cli *client) GetRawTxPool(ctx context.Context, verbose *bool) (*types.RawTxPool, error) { +func (cli *client) GetRawTxPool(ctx context.Context) (*types.RawTxPool, error) { var txPool types.RawTxPool - if verbose == nil { - defaultVerbose := false - verbose = &defaultVerbose + err := cli.c.CallContext(ctx, &txPool, "get_raw_tx_pool") + if err != nil { + return nil, err } - err := cli.c.CallContext(ctx, &txPool, "get_raw_tx_pool", verbose) + + return &txPool, err +} + +func (cli *client) GetRawTxPoolVerbose(ctx context.Context) (*types.RawTxPoolVerbose, error) { + var txPool types.RawTxPoolVerbose + + err := cli.c.CallContext(ctx, &txPool, "get_raw_tx_pool", true) if err != nil { return nil, err } @@ -996,7 +1005,7 @@ func (cli *client) RemoveTransaction(ctx context.Context, tx_hash types.Hash) (b return result, nil } -func (cli *client) SendAlert(ctx context.Context, alert types.AlertMessage) error { +func (cli *client) SendAlert(ctx context.Context, alert types.Alert) error { return cli.c.CallContext(ctx, nil, "send_alert", alert) } diff --git a/rpc/client_test.go b/rpc/client_test.go index 2dd5ed1..f8df889 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -375,13 +375,21 @@ func TestClient_ClearTxPool(t *testing.T) { } func TestClient_GetRawTxPool(t *testing.T) { - rawTxPool, err := testClient.GetRawTxPool(ctx, nil) + rawTxPool, err := testClient.GetRawTxPool(ctx) if err != nil { t.Fatal(err) } assert.NotNil(t, rawTxPool) } +func TestClient_GetRawTxPoolVerbose(t *testing.T) { + rawTxPoolVerbose, err := testClient.GetRawTxPoolVerbose(ctx) + if err != nil { + t.Fatal(err) + } + assert.NotNil(t, rawTxPoolVerbose) +} + func TestClient_GetBlockchainInfo(t *testing.T) { blockchainInfo, err := testClient.GetBlockchainInfo(ctx) if err != nil { @@ -557,3 +565,11 @@ func TestClient_GetTransactions_ExactMode(t *testing.T) { assert.NotEqual(t, 0, resp2.Objects[0].BlockNumber) assert.NotEqual(t, "", resp2.Objects[0].IoType) } + +func TestClient_GetPoolTxDetailInfo(t *testing.T) { + info, err := testClient.GetPoolTxDetailInfo(ctx, types.HexToHash("0x8277d74d33850581f8d843613ded0c2a1722dec0e87e748f45c115dfb14210f1")) + if err != nil { + t.Fatal(err) + } + assert.NotNil(t, info) +} diff --git a/types/json.go b/types/json.go index 7c421ae..1f1d38e 100644 --- a/types/json.go +++ b/types/json.go @@ -3,9 +3,10 @@ package types import ( "encoding/json" "fmt" - "github.com/ethereum/go-ethereum/common/hexutil" "math/big" "strings" + + "github.com/ethereum/go-ethereum/common/hexutil" ) func (r *ScriptType) UnmarshalJSON(input []byte) error { @@ -863,3 +864,406 @@ func (r *PackedBlock) UnmarshalJSON(input []byte) error { } return nil } + +type jsonCellbaseTemplate struct { + Hash Hash `json:"hash"` + Cycles *hexutil.Uint64 `json:"cycles"` + Data Transaction `json:"data"` +} + +var _ json.Marshaler = new(CellbaseTemplate) +var _ json.Unmarshaler = new(CellbaseTemplate) + +func (r *CellbaseTemplate) MarshalJSON() ([]byte, error) { + jsonObj := &jsonCellbaseTemplate{ + Hash: r.Hash, + Data: r.Data, + } + if r.Cycles != nil { + jsonObj.Cycles = (*hexutil.Uint64)(r.Cycles) + } + return json.Marshal(jsonObj) +} + +func (r *CellbaseTemplate) UnmarshalJSON(input []byte) error { + var jsonObj jsonCellbaseTemplate + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = CellbaseTemplate{ + Hash: jsonObj.Hash, + Data: jsonObj.Data, + } + if jsonObj.Cycles != nil { + r.Cycles = (*uint64)(jsonObj.Cycles) + } + return nil +} + +type jsonBlockTemplate struct { + Version hexutil.Uint `json:"version"` + CompactTarget hexutil.Uint `json:"compact_target"` + CurrentTime hexutil.Uint64 `json:"current_time"` + Number hexutil.Uint64 `json:"number"` + Epoch hexutil.Uint64 `json:"epoch"` + ParentHash Hash `json:"parent_hash"` + CyclesLimit hexutil.Uint64 `json:"cycles_limit"` + BytesLimit uint64 `json:"bytes_limit"` + UnclesCountLimit hexutil.Uint64 `json:"uncles_count_limit"` + Uncles []UncleTemplate `json:"uncles"` + Transactions []TransactionTemplate `json:"transactions"` + Proposals []string `json:"proposals"` + Cellbase CellbaseTemplate `json:"cellbase"` + WorkId hexutil.Uint64 `json:"work_id"` + Dao Hash `json:"dao"` + Extension *json.RawMessage `json:"extension"` +} + +var _ json.Marshaler = new(BlockTemplate) +var _ json.Unmarshaler = new(BlockTemplate) + +func (r *BlockTemplate) MarshalJSON() ([]byte, error) { + jsonObj := &jsonBlockTemplate{ + Version: hexutil.Uint(r.Version), + CompactTarget: hexutil.Uint(r.CompactTarget), + CurrentTime: hexutil.Uint64(r.CurrentTime), + Number: hexutil.Uint64(r.Number), + Epoch: hexutil.Uint64(r.Epoch), + ParentHash: r.ParentHash, + CyclesLimit: hexutil.Uint64(r.CyclesLimit), + BytesLimit: r.BytesLimit, + UnclesCountLimit: hexutil.Uint64(r.UnclesCountLimit), + Uncles: r.Uncles, + Transactions: r.Transactions, + Proposals: r.Proposals, + Cellbase: r.Cellbase, + WorkId: hexutil.Uint64(r.WorkId), + Dao: r.Dao, + } + if r.Extension != nil { + jsonObj.Extension = r.Extension + } + return json.Marshal(jsonObj) +} + +func (r *BlockTemplate) UnmarshalJSON(input []byte) error { + var jsonObj jsonBlockTemplate + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = BlockTemplate{ + Version: uint32(jsonObj.Version), + CompactTarget: uint32(jsonObj.CompactTarget), + CurrentTime: uint64(jsonObj.CurrentTime), + Number: uint64(jsonObj.Number), + Epoch: uint64(jsonObj.Epoch), + ParentHash: jsonObj.ParentHash, + CyclesLimit: uint64(jsonObj.CyclesLimit), + BytesLimit: jsonObj.BytesLimit, + UnclesCountLimit: uint64(jsonObj.UnclesCountLimit), + Uncles: jsonObj.Uncles, + Transactions: jsonObj.Transactions, + Proposals: jsonObj.Proposals, + Cellbase: jsonObj.Cellbase, + WorkId: uint64(jsonObj.WorkId), + Dao: jsonObj.Dao, + } + if jsonObj.Extension != nil { + r.Extension = jsonObj.Extension + } + return nil +} + +type jsonAncestorsScoreSortKey struct { + AncestorsFee hexutil.Uint64 `json:"ancestors_fee"` + AncestorsWeight hexutil.Uint64 `json:"ancestors_weight"` + Fee hexutil.Uint64 `json:"fee"` + Weight hexutil.Uint64 `json:"weight"` +} + +var _ json.Marshaler = new(AncestorsScoreSortKey) +var _ json.Unmarshaler = new(AncestorsScoreSortKey) + +func (r AncestorsScoreSortKey) MarshalJSON() ([]byte, error) { + jsonObj := &jsonAncestorsScoreSortKey{ + AncestorsFee: hexutil.Uint64(r.AncestorsFee), + AncestorsWeight: hexutil.Uint64(r.AncestorsWeight), + Fee: hexutil.Uint64(r.Fee), + Weight: hexutil.Uint64(r.Weight), + } + return json.Marshal(jsonObj) +} + +func (r *AncestorsScoreSortKey) UnmarshalJSON(input []byte) error { + var jsonObj jsonAncestorsScoreSortKey + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = AncestorsScoreSortKey{ + AncestorsFee: uint64(jsonObj.AncestorsFee), + AncestorsWeight: uint64(jsonObj.AncestorsWeight), + Fee: uint64(jsonObj.Fee), + Weight: uint64(jsonObj.Weight), + } + return nil +} + +type jsonPoolTxDetailInfo struct { + AncestorsCount hexutil.Uint64 `json:"ancestors_count"` + DescendantsCount hexutil.Uint64 `json:"descendants_count"` + EntryStatus string `json:"entry_status"` + PendingCount hexutil.Uint64 `json:"pending_count"` + ProposedCount hexutil.Uint64 `json:"proposed_count"` + RankInPending hexutil.Uint64 `json:"rank_in_pending"` + ScoreSortKey AncestorsScoreSortKey `json:"score_sortkey"` + Timestamp hexutil.Uint64 `json:"timestamp"` +} + +var _ json.Marshaler = new(PoolTxDetailInfo) +var _ json.Unmarshaler = new(PoolTxDetailInfo) + +func (r PoolTxDetailInfo) MarshalJSON() ([]byte, error) { + jsonObj := &jsonPoolTxDetailInfo{ + AncestorsCount: hexutil.Uint64(r.AncestorsCount), + DescendantsCount: hexutil.Uint64(r.DescendantsCount), + EntryStatus: r.EntryStatus, + PendingCount: hexutil.Uint64(r.PendingCount), + ProposedCount: hexutil.Uint64(r.ProposedCount), + RankInPending: hexutil.Uint64(r.RankInPending), + ScoreSortKey: r.ScoreSortKey, + Timestamp: hexutil.Uint64(r.Timestamp), + } + return json.Marshal(jsonObj) +} + +func (r *PoolTxDetailInfo) UnmarshalJSON(input []byte) error { + var jsonObj jsonPoolTxDetailInfo + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = PoolTxDetailInfo{ + AncestorsCount: uint64(jsonObj.AncestorsCount), + DescendantsCount: uint64(jsonObj.DescendantsCount), + EntryStatus: jsonObj.EntryStatus, + PendingCount: uint64(jsonObj.PendingCount), + ProposedCount: uint64(jsonObj.ProposedCount), + RankInPending: uint64(jsonObj.RankInPending), + ScoreSortKey: jsonObj.ScoreSortKey, + Timestamp: uint64(jsonObj.Timestamp), + } + return nil +} + +type jsonAlert struct { + Id hexutil.Uint `json:"id"` + Cancel hexutil.Uint `json:"cancel"` + MinVersion *string `json:"min_version"` + MaxVersion *string `json:"max_version"` + Priority hexutil.Uint `json:"priority"` + NoticeUntil hexutil.Uint64 `json:"notice_until"` + Message string `json:"message"` + Signatures []json.RawMessage `json:"signatures"` +} + +var _ json.Marshaler = new(Alert) +var _ json.Unmarshaler = new(Alert) + +func (r Alert) MarshalJSON() ([]byte, error) { + jsonObj := &jsonAlert{ + Id: hexutil.Uint(r.Id), + Cancel: hexutil.Uint(r.Cancel), + Priority: hexutil.Uint(r.Priority), + NoticeUntil: hexutil.Uint64(r.NoticeUntil), + Message: r.Message, + Signatures: r.Signatures, + } + if r.MinVersion != nil { + jsonObj.MinVersion = r.MinVersion + } + if r.MaxVersion != nil { + jsonObj.MaxVersion = r.MaxVersion + } + return json.Marshal(jsonObj) +} + +func (r *Alert) UnmarshalJSON(input []byte) error { + var jsonObj jsonAlert + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = Alert{ + Id: uint32(jsonObj.Id), + Cancel: uint32(jsonObj.Cancel), + Priority: uint32(jsonObj.Priority), + NoticeUntil: uint64(jsonObj.NoticeUntil), + Message: jsonObj.Message, + Signatures: jsonObj.Signatures, + } + if jsonObj.MinVersion != nil { + r.MinVersion = jsonObj.MinVersion + } + if jsonObj.MaxVersion != nil { + r.MaxVersion = jsonObj.MaxVersion + } + return nil +} + +type jsonAlertMessage struct { + Id hexutil.Uint `json:"id"` + Message string `json:"message"` + NoticeUntil hexutil.Uint64 `json:"notice_until"` + Priority hexutil.Uint `json:"priority"` +} + +func (r AlertMessage) MarshalJSON() ([]byte, error) { + jsonObj := &jsonAlertMessage{ + Id: hexutil.Uint(r.Id), + Message: r.Message, + NoticeUntil: hexutil.Uint64(r.NoticeUntil), + Priority: hexutil.Uint(r.Priority), + } + return json.Marshal(jsonObj) +} + +func (r *AlertMessage) UnmarshalJSON(input []byte) error { + var jsonObj jsonAlertMessage + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = AlertMessage{ + Id: uint32(jsonObj.Id), + Message: jsonObj.Message, + NoticeUntil: uint64(jsonObj.NoticeUntil), + Priority: uint32(jsonObj.Priority), + } + return nil +} + +type jsonDeploymentInfo struct { + Bit hexutil.Uint `json:"bit"` + Start hexutil.Uint64 `json:"start"` + Timeout hexutil.Uint64 `json:"timeout"` + MinActivationEpoch hexutil.Uint64 `json:"min_activation_epoch"` + Period hexutil.Uint64 `json:"period"` + Threshold jsonRationalU256 `json:"threshold"` + Since hexutil.Uint64 `json:"since"` + State DeploymentState `json:"state"` +} + +var _ json.Marshaler = new(DeploymentInfo) +var _ json.Unmarshaler = new(DeploymentInfo) + +func (r DeploymentInfo) MarshalJSON() ([]byte, error) { + jsonObj := &jsonDeploymentInfo{ + Bit: hexutil.Uint(r.Bit), + Start: hexutil.Uint64(r.Start), + Timeout: hexutil.Uint64(r.Timeout), + MinActivationEpoch: hexutil.Uint64(r.MinActivationEpoch), + Period: hexutil.Uint64(r.Period), + Threshold: r.Threshold, + Since: hexutil.Uint64(r.Since), + State: r.State, + } + return json.Marshal(jsonObj) +} +func (r *DeploymentInfo) UnmarshalJSON(input []byte) error { + var jsonObj jsonDeploymentInfo + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = DeploymentInfo{ + Bit: uint8(jsonObj.Bit), + Start: uint64(jsonObj.Start), + Timeout: uint64(jsonObj.Timeout), + MinActivationEpoch: uint64(jsonObj.MinActivationEpoch), + Period: uint64(jsonObj.Period), + Threshold: jsonObj.Threshold, + Since: uint64(jsonObj.Since), + State: jsonObj.State, + } + return nil +} + +type jsonDeploymentsInfo struct { + Hash Hash `json:"hash"` + Epoch hexutil.Uint64 `json:"epoch"` + Deployments map[string]DeploymentInfo `json:"deployments"` +} + +var _ json.Marshaler = new(DeploymentsInfo) +var _ json.Unmarshaler = new(DeploymentsInfo) + +func (r DeploymentsInfo) MarshalJSON() ([]byte, error) { + deployments := make(map[string]DeploymentInfo) + for k, v := range r.Deployments { + deployments[k.String()] = v + } + jsonObj := &jsonDeploymentsInfo{ + Hash: r.Hash, + Epoch: hexutil.Uint64(r.Epoch), + Deployments: deployments, + } + return json.Marshal(jsonObj) +} +func (r *DeploymentsInfo) UnmarshalJSON(input []byte) error { + var jsonObj jsonDeploymentsInfo + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + deployments := make(map[DeploymentPos]DeploymentInfo) + for k, v := range jsonObj.Deployments { + pos, err := DeploymentPosFromString(k) + if err != nil { + return err + } + deployments[pos] = v + } + *r = DeploymentsInfo{ + Hash: jsonObj.Hash, + Epoch: uint64(jsonObj.Epoch), + Deployments: deployments, + } + return nil +} + +type jsonTxPoolEntry struct { + Cycles hexutil.Uint64 `json:"cycles"` + Size hexutil.Uint64 `json:"size"` + Fee hexutil.Uint64 `json:"fee"` + AncestorsSize hexutil.Uint64 `json:"ancestors_size"` + AncestorsCycles hexutil.Uint64 `json:"ancestors_cycles"` + AncestorsCount hexutil.Uint64 `json:"ancestors_count"` + Timestamp hexutil.Uint64 `json:"timestamp"` +} + +var _ json.Marshaler = new(TxPoolEntry) +var _ json.Unmarshaler = new(TxPoolEntry) + +func (r TxPoolEntry) MarshalJSON() ([]byte, error) { + jsonObj := &jsonTxPoolEntry{ + Cycles: hexutil.Uint64(r.Cycles), + Size: hexutil.Uint64(r.Size), + Fee: hexutil.Uint64(r.Fee), + AncestorsSize: hexutil.Uint64(r.AncestorsSize), + AncestorsCycles: hexutil.Uint64(r.AncestorsCycles), + AncestorsCount: hexutil.Uint64(r.AncestorsCount), + Timestamp: hexutil.Uint64(r.Timestamp), + } + return json.Marshal(jsonObj) +} +func (r *TxPoolEntry) UnmarshalJSON(input []byte) error { + var jsonObj jsonTxPoolEntry + if err := json.Unmarshal(input, &jsonObj); err != nil { + return err + } + *r = TxPoolEntry{ + Cycles: uint64(jsonObj.Cycles), + Size: uint64(jsonObj.Size), + Fee: uint64(jsonObj.Fee), + AncestorsSize: uint64(jsonObj.AncestorsSize), + AncestorsCycles: uint64(jsonObj.AncestorsCycles), + AncestorsCount: uint64(jsonObj.AncestorsCount), + Timestamp: uint64(jsonObj.Timestamp), + } + return nil +} diff --git a/types/pool.go b/types/pool.go index 8aed1ae..a1fab05 100644 --- a/types/pool.go +++ b/types/pool.go @@ -80,6 +80,22 @@ type RawTxPool struct { Proposed []Hash `json:"proposed"` } +type RawTxPoolVerbose struct { + Pending map[Hash]TxPoolEntry `json:"pending"` + Proposed map[Hash]TxPoolEntry `json:"proposed"` + Confilicted []Hash `json:"conflicted"` +} + +type TxPoolEntry struct { + Cycles uint64 `json:"cycles"` + Size uint64 `json:"size"` + Fee uint64 `json:"fee"` + AncestorsSize uint64 `json:"ancestors_size"` + AncestorsCycles uint64 `json:"ancestors_cycles"` + AncestorsCount uint64 `json:"ancestors_count"` + Timestamp uint64 `json:"timestamp"` +} + type AncestorsScoreSortKey struct { AncestorsFee uint64 `json:"ancestors_fee"` AncestorsWeight uint64 `json:"ancestors_weight"` diff --git a/types/stats.go b/types/stats.go index 975b4bc..4261936 100644 --- a/types/stats.go +++ b/types/stats.go @@ -1,7 +1,10 @@ package types -import "math/big" -import "encoding/json" +import ( + "encoding/json" + "fmt" + "math/big" +) // pub struct Alert { // /// The identifier of the alert. Clients use id to filter duplicated alerts. @@ -78,6 +81,28 @@ const ( LightClient ) +// convert DeploymentPos to string +func (d DeploymentPos) String() string { + switch d { + case Testdummy: + return "Testdummy" + case LightClient: + return "LightClient" + } + return "Unknown" +} + +// convert string to DeploymentPos +func DeploymentPosFromString(s string) (DeploymentPos, error) { + switch s { + case "Testdummy": + return Testdummy, nil + case "LightClient": + return LightClient, nil + } + return -1, fmt.Errorf("invalid DeploymentPos: %s", s) +} + // DeploymentInfo represents information about a deployment. type DeploymentInfo struct { Bit uint8