From 3dd25c2cd0f3383eb1d4d456ccfacc9aeae09cb0 Mon Sep 17 00:00:00 2001 From: Matee ullah Malik <46045452+mateeullahmalik@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:42:12 +0300 Subject: [PATCH] [PSL-1193] create multi-volume cascade ticket (#886) * [PSL-1193] * [PSL-1193] get cascade-multi-volume contract --------- Co-authored-by: Matee Ullah --- pastel/client.go | 54 ++++++++++++++++++++++++++++++++++++++ pastel/contract.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++ pastel/pastel.go | 8 ++++++ 3 files changed, 127 insertions(+) create mode 100644 pastel/contract.go diff --git a/pastel/client.go b/pastel/client.go index 5a015d0c6..2ac3f66ea 100644 --- a/pastel/client.go +++ b/pastel/client.go @@ -3,6 +3,7 @@ package pastel import ( "context" "encoding/base64" + "encoding/json" "fmt" "net" "strconv" @@ -11,6 +12,7 @@ import ( "github.com/pastelnetwork/gonode/common/errors" "github.com/pastelnetwork/gonode/common/log" + "github.com/pastelnetwork/gonode/common/utils" "github.com/pastelnetwork/gonode/pastel/jsonrpc" ) @@ -23,8 +25,13 @@ const ( TicketTypeInactive RegTicketsFilter = "inactive" // TicketTypeAll is all filter for tickets TicketTypeAll RegTicketsFilter = "all" + + // CascadeMultiVolumeMetadata is the only contract type currently available + CascadeMultiVolumeMetadata ContractType = "cascade_multi_volume_metadata" ) +type ContractType string + // RegTicketsFilter is filter for retrieving action & nft registration tickets type RegTicketsFilter string @@ -288,6 +295,16 @@ func (client *client) RegTicket(ctx context.Context, regTxid string) (RegTicket, return ticket, nil } +func (client *client) GetContractTicket(ctx context.Context, txid string) (Contract, error) { + ticket := Contract{} + + if err := client.callFor(ctx, &ticket, "tickets", "get", txid); err != nil { + return ticket, errors.Errorf("failed to get contract ticket %s: %w", txid, err) + } + + return ticket, nil +} + // ActionRegTicket implements pastel.Client.RegTicket func (client *client) ActionRegTicket(ctx context.Context, regTxid string) (ActionRegTicket, error) { ticket := ActionRegTicket{} @@ -531,6 +548,43 @@ func (client *client) RegisterActionTicket(ctx context.Context, request Register return txID.TxID, nil } +func (client *client) RegisterCascadeMultiVolumeTicket(ctx context.Context, ticket CascadeMultiVolumeTicket) (string, error) { + return client.registerContract(ctx, ticket, CascadeMultiVolumeMetadata) +} + +func (client *client) registerContract(ctx context.Context, data interface{}, contractType ContractType) (string, error) { + ticketJSON, err := json.Marshal(data) + if err != nil { + return "", errors.Errorf("failed to call register action ticket: %w", err) + } + ticketBlob := base64.StdEncoding.EncodeToString(ticketJSON) + + hash, _ := utils.Sha3256hash(ticketJSON) + // Assuming some additional data or parameters are needed, similar to the RegisterNFTRequest example + params := []interface{}{ + "register", + "contract", + ticketBlob, + contractType, + hash, + } + + type ContractResponse struct { + TxID string `json:"txid"` + Key string `json:"key"` + } + resp := ContractResponse{} + + if err := client.callFor(ctx, &resp, "tickets", params...); err != nil { + return "", errors.Errorf("failed to call register contract: %w", err) + } + if resp.TxID == "" { + return "", errors.Errorf("failed to call register contract (no txid rcvd.): %w", err) + } + + return resp.TxID, nil +} + func (client *client) ActivateActionTicket(ctx context.Context, request ActivateActionRequest) (string, error) { var txID struct { TxID string `json:"txid"` diff --git a/pastel/contract.go b/pastel/contract.go new file mode 100644 index 000000000..526b7d618 --- /dev/null +++ b/pastel/contract.go @@ -0,0 +1,65 @@ +package pastel + +import ( + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/pastelnetwork/gonode/common/errors" +) + +// ContractTicket defines the contract ticket +type ContractTicket struct { + ContractTicketData string `json:"contract_ticket"` + Key string `json:"key"` + SecondaryKey string `json:"secondary_key"` + SubType string `json:"sub_type"` + Timestamp int64 `json:"timestamp"` + Type string `json:"type"` + Version int `json:"version"` +} + +// TxInfo defines the transaction information +type TxInfo struct { + CompressedSize int `json:"compressed_size"` + CompressionRatio string `json:"compression_ratio"` + IsCompressed bool `json:"is_compressed"` + MultisigOutputsCount int `json:"multisig_outputs_count"` + MultisigTxTotalFee int `json:"multisig_tx_total_fee"` + UncompressedSize int `json:"uncompressed_size"` +} + +// Contract defines the contract +type Contract struct { + Height int `json:"height"` + Ticket ContractTicket `json:"ticket"` + TxInfo TxInfo `json:"tx_info"` + TxID string `json:"txid"` +} + +// -------------------------------------- Contract Types -------------------------------------------// + +// CascadeMultiVolumeTicket defines the cascade multi volume ticket contract type +type CascadeMultiVolumeTicket struct { + NameOfOriginalFile string `json:"name_of_original_file"` + SizeOfOriginalFileMB int `json:"size_of_original_file_mb"` + SHA3256HashOfOriginalFile string `json:"sha3_256_hash_of_original_file"` + Volumes map[int]string `json:"volumes"` // key (int): index of the volume, value (string): txid of the volume +} + +func (c *Contract) GetCascadeMultiVolumeMetadataTicket() (t CascadeMultiVolumeTicket, err error) { + if c.Ticket.SubType != string(CascadeMultiVolumeMetadata) { + return t, errors.New("contract is not of type cascade_multi_volume_metadata") + } + + data, err := base64.StdEncoding.DecodeString(c.Ticket.ContractTicketData) + if err != nil { + return t, fmt.Errorf("unable to b64 decode contract: %w", err) + } + + if err := json.Unmarshal(data, &t); err != nil { + return t, fmt.Errorf("unable to decode contract: %w", err) + } + + return t, nil +} diff --git a/pastel/pastel.go b/pastel/pastel.go index ed6e1067b..9db6a7de8 100644 --- a/pastel/pastel.go +++ b/pastel/pastel.go @@ -239,4 +239,12 @@ type Client interface { //NFTStorageFee returns the fee of NFT storage //Command `tickets tools estimatenftstoragefee ` NFTStorageFee(ctx context.Context, sizeInMB int) (*NFTStorageFeeEstimate, error) + + // RegisterCascadeMultiVolumeTicket registers a cascade multi-volume ticket + // Command `tickets register contract <>, <>, <>` + RegisterCascadeMultiVolumeTicket(ctx context.Context, ticket CascadeMultiVolumeTicket) (string, error) + + // GetContractTicket returns contract ticket. + // Command `tickets get `. + GetContractTicket(ctx context.Context, txid string) (Contract, error) }