From 969b04a9ad50a6d0fbf0700577b581d4e32f7fc2 Mon Sep 17 00:00:00 2001 From: wregulski Date: Thu, 25 May 2023 12:31:17 +0200 Subject: [PATCH] feat: moves models to specific directories --- apis/mapi/fee_quote.go | 174 +++++++++++++++++ apis/mapi/policy_quote.go | 111 +++++++++++ examples/best_quote/best_quote.go | 3 +- examples/calculate_fee/calculate_fee.go | 3 +- examples/fee_quote/fee_quote.go | 3 +- examples/policy_quote/policy_quote.go | 4 +- .../submit_transaction/submit_transaction.go | 2 +- fee_quote.go | 179 +----------------- policy_quote.go | 118 +----------- 9 files changed, 305 insertions(+), 292 deletions(-) create mode 100644 apis/mapi/fee_quote.go create mode 100644 apis/mapi/policy_quote.go diff --git a/apis/mapi/fee_quote.go b/apis/mapi/fee_quote.go new file mode 100644 index 0000000..60d94bc --- /dev/null +++ b/apis/mapi/fee_quote.go @@ -0,0 +1,174 @@ +package mapi + +import ( + "fmt" + "strings" + + "github.com/libsv/go-bt/v2" +) + +const ( + + // FeeTypeData is the key corresponding to the data rate + FeeTypeData = "data" + + // FeeTypeStandard is the key corresponding to the standard rate + FeeTypeStandard = "standard" + + // FeeCategoryMining is the category corresponding to the mining rate + FeeCategoryMining = "mining" + + // FeeCategoryRelay is the category corresponding to the relay rate + FeeCategoryRelay = "relay" +) + +/* +Example feeQuote response from Merchant API: + +{ + "payload": "{\"apiVersion\":\"1.4.0\",\"timestamp\":\"2020-10-07T21:13:04.335Z\",\"expiryTime\":\"2020-10-07T21:23:04.335Z\",\"minerId\":\"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087\",\"currentHighestBlockHash\":\"000000000000000000edb30c3bbbc8e6a07e522e85522e6a213f7e933e6e2d8d\",\"currentHighestBlockHeight\":655874,\"minerReputation\":null,\"fees\":[{\"feeType\":\"standard\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}},{\"feeType\":\"data\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}}]}", + "signature": "304402206443bea5bdd98a16e23eb61c36b4b998bd68ceb9c84983c7e695e267b21a30440220191571e9b9632c8337d9196723ca20eefa63966ef6360170db0e57a04047453f", + "publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087", + "encoding": "UTF-8", + "mimetype": "application/json" +} +*/ + +/* +Example FeeQuoteResponse.Payload (unmarshalled): + +{ + "apiVersion": "1.4.0", + "timestamp": "2020-10-07T21:13:04.335Z", + "expiryTime": "2020-10-07T21:23:04.335Z", + "minerId": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087", + "currentHighestBlockHash": "000000000000000000edb30c3bbbc8e6a07e522e85522e6a213f7e933e6e2d8d", + "currentHighestBlockHeight": 655874, + "fees": [ + { + "feeType": "standard", + "miningFee": { + "satoshis": 500, + "bytes": 1000 + }, + "relayFee": { + "satoshis": 250, + "bytes": 1000 + } + }, + { + "feeType": "data", + "miningFee": { + "satoshis": 500, + "bytes": 1000 + }, + "relayFee": { + "satoshis": 250, + "bytes": 1000 + } + } + ] +} +*/ + +// FeePayload is the unmarshalled version of the payload envelope +type FeePayload struct { + FeePayloadFields + Fees []*bt.Fee `json:"fees"` +} + +type ( + + // rawFeePayload is the unmarshalled version of the payload envelope + RawFeePayload struct { + FeePayloadFields + Callbacks []*PolicyCallback `json:"callbacks"` // IP addresses of double-spend notification servers such as mAPI reference implementation + Fees []*feeObj `json:"fees"` + } + + // feePayloadFields are the same fields in both payloads + FeePayloadFields struct { + APIVersion string `json:"apiVersion"` + Timestamp string `json:"timestamp"` + ExpirationTime string `json:"expiryTime"` + MinerID string `json:"minerId"` + CurrentHighestBlockHash string `json:"currentHighestBlockHash"` + CurrentHighestBlockHeight uint64 `json:"currentHighestBlockHeight"` + MinerReputation interface{} `json:"minerReputation"` // Not sure what this value is + } + + // feeUnit displays the amount of Satoshis needed + // for a specific amount of Bytes in a transaction + // see https://github.com/bitcoin-sv-specs/brfc-merchantapi#expanded-payload-1 + FeeUnit struct { + Satoshis int `json:"satoshis"` // Fee in satoshis of the amount of Bytes + Bytes int `json:"bytes"` // Number of bytes that the Fee covers + } + + // feeObj displays the MiningFee as well as the RelayFee for a specific + // FeeType, for example 'standard' or 'data' + // see https://github.com/bitcoin-sv-specs/brfc-merchantapi#expanded-payload-1 + feeObj struct { + FeeType string `json:"feeType"` // standard || data + MiningFee FeeUnit `json:"miningFee"` + RelayFee FeeUnit `json:"relayFee"` // Fee for retaining Tx in secondary mempool + } +) + +// CalculateFee will return the fee for the given txBytes +// Type: "FeeTypeData" or "FeeTypeStandard" +// Category: "FeeCategoryMining" or "FeeCategoryRelay" +// +// If no fee is found or fee is 0, returns 1 & error +// +// Spec: https://github.com/bitcoin-sv-specs/brfc-misc/tree/master/feespec#deterministic-transaction-fee-calculation-dtfc +func (f *FeePayload) CalculateFee(feeCategory, feeType string, txBytes uint64) (uint64, error) { + + // Valid feeType? + if !strings.EqualFold(feeType, FeeTypeData) && !strings.EqualFold(feeType, FeeTypeStandard) { + return 0, fmt.Errorf("feeType %s is not recognized", feeType) + } else if !strings.EqualFold(feeCategory, FeeCategoryMining) && !strings.EqualFold(feeCategory, FeeCategoryRelay) { + return 0, fmt.Errorf("feeCategory %s is not recognized", feeCategory) + } + + // Loop all fee types looking for feeType (data or standard) + for _, fee := range f.Fees { + + // Detect the type (data or standard) + if string(fee.FeeType) != feeType { + continue + } + + // Multiply & Divide + var calcFee uint64 + if strings.EqualFold(feeCategory, FeeCategoryMining) { + calcFee = (uint64(fee.MiningFee.Satoshis) * txBytes) / uint64(fee.MiningFee.Bytes) + } else { + calcFee = (uint64(fee.RelayFee.Satoshis) * txBytes) / uint64(fee.RelayFee.Bytes) + } + + // Check for zero + if calcFee != 0 { + return calcFee, nil + } + + // If txBytes is zero this error will occur + return 1, fmt.Errorf("warning: fee calculation was 0") + } + + // No fee type found in the slice of fees + return 1, fmt.Errorf("feeType %s is not found in fees", feeType) +} + +// GetFee will return the fee associated to the type (standard, data) +func (f *FeePayload) GetFee(feeType string) *bt.Fee { + + // Loop the fees for the given type + for index, fee := range f.Fees { + if string(fee.FeeType) == feeType { + return f.Fees[index] + } + } + + return nil +} diff --git a/apis/mapi/policy_quote.go b/apis/mapi/policy_quote.go new file mode 100644 index 0000000..dbfbfca --- /dev/null +++ b/apis/mapi/policy_quote.go @@ -0,0 +1,111 @@ +package mapi + +/* +Example PolicyQuoteResponse.Payload (unmarshalled): + +{ + "apiVersion": "1.4.0", + "timestamp": "2021-11-12T13:17:47.7498672Z", + "expiryTime": "2021-11-12T13:27:47.7498672Z", + "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e", + "currentHighestBlockHash": "45628be2fe616167b7da399ab63455e60ffcf84147730f4af4affca90c7d437e", + "currentHighestBlockHeight": 234, + "fees": [ + { + "feeType": "standard", + "miningFee": { + "satoshis": 500, + "bytes": 1000 + }, + "relayFee": { + "satoshis": 250, + "bytes": 1000 + } + }, + { + "feeType": "data", + "miningFee": { + "satoshis": 500, + "bytes": 1000 + }, + "relayFee": { + "satoshis": 250, + "bytes": 1000 + } + } + ], + "callbacks": [ + { + "ipAddress": "123.456.789.123" + } + ], + "policies": { + "skipscriptflags": [ + "MINIMALDATA", + "DERSIG", + "NULLDUMMY", + "DISCOURAGE_UPGRADABLE_NOPS", + "CLEANSTACK" + ], + "maxtxsizepolicy": 99999, + "datacarriersize": 100000, + "maxscriptsizepolicy": 100000, + "maxscriptnumlengthpolicy": 100000, + "maxstackmemoryusagepolicy": 10000000, + "limitancestorcount": 1000, + "limitcpfpgroupmemberscount": 10, + "acceptnonstdoutputs": true, + "datacarrier": true, + "maxstdtxvalidationduration": 99, + "maxnonstdtxvalidationduration": 100, + "minconsolidationfactor": 10, + "maxconsolidationinputscriptsize": 100, + "minconfconsolidationinput": 10, + "acceptnonstdconsolidationinput": false + } +} +*/ + +// PolicyPayload is the unmarshalled version of the payload envelope +type PolicyPayload struct { + FeePayload // Inherit the same structure as the fee payload + Callbacks []*PolicyCallback `json:"callbacks"` // IP addresses of double-spend notification servers such as mAPI reference implementation + Policies *Policy `json:"policies"` // values of miner policies as configured by the mAPI reference implementation administrator +} + +// ScriptFlag is a flag used in the policy quote +type ScriptFlag string + +// All known script flags +const ( + FlagCleanStack ScriptFlag = "CLEANSTACK" + FlagDerSig ScriptFlag = "DERSIG" + FlagDiscourageUpgradableNops ScriptFlag = "DISCOURAGE_UPGRADABLE_NOPS" + FlagMinimalData ScriptFlag = "MINIMALDATA" + FlagNullDummy ScriptFlag = "NULLDUMMY" +) + +// Policy is the struct of a policy (from policy quote response) +type Policy struct { + AcceptNonStdOutputs bool `json:"acceptnonstdoutputs"` + DataCarrier bool `json:"datacarrier"` + DataCarrierSize uint32 `json:"datacarriersize"` + LimitAncestorCount uint32 `json:"limitancestorcount"` + LimitCpfpGroupMembersCount uint32 `json:"limitcpfpgroupmemberscount"` + MaxNonStdTxValidationDuration uint32 `json:"maxnonstdtxvalidationduration"` + MaxScriptNumLengthPolicy uint32 `json:"maxscriptnumlengthpolicy"` + MaxScriptSizePolicy uint32 `json:"maxscriptsizepolicy"` + MaxStackMemoryUsagePolicy uint64 `json:"maxstackmemoryusagepolicy"` + MaxStdTxValidationDuration uint32 `json:"maxstdtxvalidationduration"` + MaxTxSizePolicy uint32 `json:"maxtxsizepolicy"` + SkipScriptFlags []ScriptFlag `json:"skipscriptflags"` + MaxConsolidationFactor uint32 `json:"minconsolidationfactor"` + MaxConsolidationInputScriptSize uint32 `json:"maxconsolidationinputscriptsize"` + MinConfConsolidationInput uint32 `json:"minconfconsolidationinput"` + AcceptNonStdConsolidationInput bool `json:"acceptnonstdconsolidationinput"` +} + +// PolicyCallback is the callback address +type PolicyCallback struct { + IPAddress string `json:"ipAddress"` +} diff --git a/examples/best_quote/best_quote.go b/examples/best_quote/best_quote.go index 9cc5fae..77bc925 100644 --- a/examples/best_quote/best_quote.go +++ b/examples/best_quote/best_quote.go @@ -5,6 +5,7 @@ import ( "log" "github.com/tonicpow/go-minercraft" + "github.com/tonicpow/go-minercraft/apis/mapi" ) func main() { @@ -19,7 +20,7 @@ func main() { // Fetch quotes from all miners var response *minercraft.FeeQuoteResponse - response, err = client.BestQuote(context.Background(), minercraft.FeeCategoryMining, minercraft.FeeTypeData) + response, err = client.BestQuote(context.Background(), mapi.FeeCategoryMining, mapi.FeeTypeData) if err != nil { log.Fatalf("error occurred: %s", err.Error()) } diff --git a/examples/calculate_fee/calculate_fee.go b/examples/calculate_fee/calculate_fee.go index af3a277..3b54519 100644 --- a/examples/calculate_fee/calculate_fee.go +++ b/examples/calculate_fee/calculate_fee.go @@ -5,6 +5,7 @@ import ( "log" "github.com/tonicpow/go-minercraft" + "github.com/tonicpow/go-minercraft/apis/mapi" ) func main() { @@ -29,7 +30,7 @@ func main() { // Get the fee for a specific tx size (for mining and for data) var fee uint64 - if fee, err = response.Quote.CalculateFee(minercraft.FeeCategoryMining, minercraft.FeeTypeStandard, txSizeInBytes); err != nil { + if fee, err = response.Quote.CalculateFee(mapi.FeeCategoryMining, mapi.FeeTypeStandard, txSizeInBytes); err != nil { log.Fatalf("error occurred: %s", err.Error()) } diff --git a/examples/fee_quote/fee_quote.go b/examples/fee_quote/fee_quote.go index 292e8f6..8735b82 100644 --- a/examples/fee_quote/fee_quote.go +++ b/examples/fee_quote/fee_quote.go @@ -5,6 +5,7 @@ import ( "log" "github.com/tonicpow/go-minercraft" + "github.com/tonicpow/go-minercraft/apis/mapi" ) func main() { @@ -29,7 +30,7 @@ func main() { // Get the fee for a specific tx size (for mining and for data) var fee uint64 - if fee, err = response.Quote.CalculateFee(minercraft.FeeCategoryMining, minercraft.FeeTypeData, txSizeInBytes); err != nil { + if fee, err = response.Quote.CalculateFee(mapi.FeeCategoryMining, mapi.FeeTypeData, txSizeInBytes); err != nil { log.Fatalf("error occurred: %s", err.Error()) } diff --git a/examples/policy_quote/policy_quote.go b/examples/policy_quote/policy_quote.go index 47a5c56..dc89121 100644 --- a/examples/policy_quote/policy_quote.go +++ b/examples/policy_quote/policy_quote.go @@ -10,13 +10,13 @@ import ( func main() { // Create a new client - client, err := minercraft.NewClient(nil, nil, "", nil, nil) + client, err := minercraft.NewClient(nil, nil, minercraft.MAPI, nil, nil) if err != nil { log.Fatalf("error occurred: %s", err.Error()) } // Select the miner - miner := client.MinerByName(minercraft.MinerTaal) + miner := client.MinerByName(minercraft.MinerGorillaPool) // Get a policy quote from a miner var response *minercraft.PolicyQuoteResponse diff --git a/examples/submit_transaction/submit_transaction.go b/examples/submit_transaction/submit_transaction.go index 1e21ea0..5be61d8 100644 --- a/examples/submit_transaction/submit_transaction.go +++ b/examples/submit_transaction/submit_transaction.go @@ -10,7 +10,7 @@ import ( func main() { // Create a new client - client, err := minercraft.NewClient(nil, nil, "", nil, nil) + client, err := minercraft.NewClient(nil, nil, minercraft.MAPI, nil, nil) if err != nil { log.Fatalf("error occurred: %s", err.Error()) } diff --git a/fee_quote.go b/fee_quote.go index 6ca9997..d382dcb 100644 --- a/fee_quote.go +++ b/fee_quote.go @@ -4,185 +4,18 @@ import ( "context" "encoding/json" "errors" - "fmt" "net/http" - "strings" "github.com/libsv/go-bt/v2" + "github.com/tonicpow/go-minercraft/apis/mapi" ) -const ( - - // FeeTypeData is the key corresponding to the data rate - FeeTypeData = "data" - - // FeeTypeStandard is the key corresponding to the standard rate - FeeTypeStandard = "standard" - - // FeeCategoryMining is the category corresponding to the mining rate - FeeCategoryMining = "mining" - - // FeeCategoryRelay is the category corresponding to the relay rate - FeeCategoryRelay = "relay" -) - -/* -Example feeQuote response from Merchant API: - -{ - "payload": "{\"apiVersion\":\"1.4.0\",\"timestamp\":\"2020-10-07T21:13:04.335Z\",\"expiryTime\":\"2020-10-07T21:23:04.335Z\",\"minerId\":\"0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087\",\"currentHighestBlockHash\":\"000000000000000000edb30c3bbbc8e6a07e522e85522e6a213f7e933e6e2d8d\",\"currentHighestBlockHeight\":655874,\"minerReputation\":null,\"fees\":[{\"feeType\":\"standard\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}},{\"feeType\":\"data\",\"miningFee\":{\"satoshis\":500,\"bytes\":1000},\"relayFee\":{\"satoshis\":250,\"bytes\":1000}}]}", - "signature": "304402206443bea5bdd98a16e23eb61c36b4b998bd68ceb9c84983c7e695e267b21a30440220191571e9b9632c8337d9196723ca20eefa63966ef6360170db0e57a04047453f", - "publicKey": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087", - "encoding": "UTF-8", - "mimetype": "application/json" -} -*/ - // FeeQuoteResponse is the raw response from the Merchant API request // // Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi#2-get-fee-quote type FeeQuoteResponse struct { JSONEnvelope - Quote *FeePayload `json:"quote"` // Custom field for unmarshalled payload data -} - -/* -Example FeeQuoteResponse.Payload (unmarshalled): - -{ - "apiVersion": "1.4.0", - "timestamp": "2020-10-07T21:13:04.335Z", - "expiryTime": "2020-10-07T21:23:04.335Z", - "minerId": "0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087", - "currentHighestBlockHash": "000000000000000000edb30c3bbbc8e6a07e522e85522e6a213f7e933e6e2d8d", - "currentHighestBlockHeight": 655874, - "fees": [ - { - "feeType": "standard", - "miningFee": { - "satoshis": 500, - "bytes": 1000 - }, - "relayFee": { - "satoshis": 250, - "bytes": 1000 - } - }, - { - "feeType": "data", - "miningFee": { - "satoshis": 500, - "bytes": 1000 - }, - "relayFee": { - "satoshis": 250, - "bytes": 1000 - } - } - ] -} -*/ - -// FeePayload is the unmarshalled version of the payload envelope -type FeePayload struct { - feePayloadFields - Fees []*bt.Fee `json:"fees"` -} - -type ( - - // rawFeePayload is the unmarshalled version of the payload envelope - rawFeePayload struct { - feePayloadFields - Callbacks []*PolicyCallback `json:"callbacks"` // IP addresses of double-spend notification servers such as mAPI reference implementation - Fees []*feeObj `json:"fees"` - } - - // feePayloadFields are the same fields in both payloads - feePayloadFields struct { - APIVersion string `json:"apiVersion"` - Timestamp string `json:"timestamp"` - ExpirationTime string `json:"expiryTime"` - MinerID string `json:"minerId"` - CurrentHighestBlockHash string `json:"currentHighestBlockHash"` - CurrentHighestBlockHeight uint64 `json:"currentHighestBlockHeight"` - MinerReputation interface{} `json:"minerReputation"` // Not sure what this value is - } - - // feeUnit displays the amount of Satoshis needed - // for a specific amount of Bytes in a transaction - // see https://github.com/bitcoin-sv-specs/brfc-merchantapi#expanded-payload-1 - feeUnit struct { - Satoshis int `json:"satoshis"` // Fee in satoshis of the amount of Bytes - Bytes int `json:"bytes"` // Number of bytes that the Fee covers - } - - // feeObj displays the MiningFee as well as the RelayFee for a specific - // FeeType, for example 'standard' or 'data' - // see https://github.com/bitcoin-sv-specs/brfc-merchantapi#expanded-payload-1 - feeObj struct { - FeeType string `json:"feeType"` // standard || data - MiningFee feeUnit `json:"miningFee"` - RelayFee feeUnit `json:"relayFee"` // Fee for retaining Tx in secondary mempool - } -) - -// CalculateFee will return the fee for the given txBytes -// Type: "FeeTypeData" or "FeeTypeStandard" -// Category: "FeeCategoryMining" or "FeeCategoryRelay" -// -// If no fee is found or fee is 0, returns 1 & error -// -// Spec: https://github.com/bitcoin-sv-specs/brfc-misc/tree/master/feespec#deterministic-transaction-fee-calculation-dtfc -func (f *FeePayload) CalculateFee(feeCategory, feeType string, txBytes uint64) (uint64, error) { - - // Valid feeType? - if !strings.EqualFold(feeType, FeeTypeData) && !strings.EqualFold(feeType, FeeTypeStandard) { - return 0, fmt.Errorf("feeType %s is not recognized", feeType) - } else if !strings.EqualFold(feeCategory, FeeCategoryMining) && !strings.EqualFold(feeCategory, FeeCategoryRelay) { - return 0, fmt.Errorf("feeCategory %s is not recognized", feeCategory) - } - - // Loop all fee types looking for feeType (data or standard) - for _, fee := range f.Fees { - - // Detect the type (data or standard) - if string(fee.FeeType) != feeType { - continue - } - - // Multiply & Divide - var calcFee uint64 - if strings.EqualFold(feeCategory, FeeCategoryMining) { - calcFee = (uint64(fee.MiningFee.Satoshis) * txBytes) / uint64(fee.MiningFee.Bytes) - } else { - calcFee = (uint64(fee.RelayFee.Satoshis) * txBytes) / uint64(fee.RelayFee.Bytes) - } - - // Check for zero - if calcFee != 0 { - return calcFee, nil - } - - // If txBytes is zero this error will occur - return 1, fmt.Errorf("warning: fee calculation was 0") - } - - // No fee type found in the slice of fees - return 1, fmt.Errorf("feeType %s is not found in fees", feeType) -} - -// GetFee will return the fee associated to the type (standard, data) -func (f *FeePayload) GetFee(feeType string) *bt.Fee { - - // Loop the fees for the given type - for index, fee := range f.Fees { - if string(fee.FeeType) == feeType { - return f.Fees[index] - } - } - - return nil + Quote *mapi.FeePayload `json:"quote"` // Custom field for unmarshalled payload data } // FeeQuote will fire a Merchant API request to retrieve the fees from a given miner @@ -238,12 +71,12 @@ func (i *internalResult) parseFeeQuote() (response FeeQuoteResponse, err error) if len(response.Payload) > 0 { // Create a raw payload shim - p := new(rawFeePayload) + p := new(mapi.RawFeePayload) if err = json.Unmarshal([]byte(response.Payload), &p); err != nil { return } if response.Quote == nil { - response.Quote = new(FeePayload) + response.Quote = new(mapi.FeePayload) } // Create the response payload @@ -253,7 +86,7 @@ func (i *internalResult) parseFeeQuote() (response FeeQuoteResponse, err error) } // rawPayloadIntoQuote will convert the raw parsed payload into a final quote payload -func rawPayloadIntoQuote(payload *rawFeePayload, quote *FeePayload) { +func rawPayloadIntoQuote(payload *mapi.RawFeePayload, quote *mapi.FeePayload) { // Set the fields from the raw payload into the quote quote.MinerID = payload.MinerID @@ -267,7 +100,7 @@ func rawPayloadIntoQuote(payload *rawFeePayload, quote *FeePayload) { // Convert the mAPI fees into go-bt fees for _, f := range payload.Fees { t := bt.FeeTypeStandard - if f.FeeType == FeeTypeData { + if f.FeeType == mapi.FeeTypeData { t = bt.FeeTypeData } quote.Fees = append(quote.Fees, &bt.Fee{ diff --git a/policy_quote.go b/policy_quote.go index 3120904..a6f1a6c 100644 --- a/policy_quote.go +++ b/policy_quote.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "errors" + + "github.com/tonicpow/go-minercraft/apis/mapi" ) /* @@ -23,117 +25,7 @@ Example policyQuote response from Merchant API: // Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi#1-get-policy-quote type PolicyQuoteResponse struct { JSONEnvelope - Quote *PolicyPayload `json:"quote"` // Custom field for unmarshalled payload data -} - -/* -Example PolicyQuoteResponse.Payload (unmarshalled): - -{ - "apiVersion": "1.4.0", - "timestamp": "2021-11-12T13:17:47.7498672Z", - "expiryTime": "2021-11-12T13:27:47.7498672Z", - "minerId": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e", - "currentHighestBlockHash": "45628be2fe616167b7da399ab63455e60ffcf84147730f4af4affca90c7d437e", - "currentHighestBlockHeight": 234, - "fees": [ - { - "feeType": "standard", - "miningFee": { - "satoshis": 500, - "bytes": 1000 - }, - "relayFee": { - "satoshis": 250, - "bytes": 1000 - } - }, - { - "feeType": "data", - "miningFee": { - "satoshis": 500, - "bytes": 1000 - }, - "relayFee": { - "satoshis": 250, - "bytes": 1000 - } - } - ], - "callbacks": [ - { - "ipAddress": "123.456.789.123" - } - ], - "policies": { - "skipscriptflags": [ - "MINIMALDATA", - "DERSIG", - "NULLDUMMY", - "DISCOURAGE_UPGRADABLE_NOPS", - "CLEANSTACK" - ], - "maxtxsizepolicy": 99999, - "datacarriersize": 100000, - "maxscriptsizepolicy": 100000, - "maxscriptnumlengthpolicy": 100000, - "maxstackmemoryusagepolicy": 10000000, - "limitancestorcount": 1000, - "limitcpfpgroupmemberscount": 10, - "acceptnonstdoutputs": true, - "datacarrier": true, - "maxstdtxvalidationduration": 99, - "maxnonstdtxvalidationduration": 100, - "minconsolidationfactor": 10, - "maxconsolidationinputscriptsize": 100, - "minconfconsolidationinput": 10, - "acceptnonstdconsolidationinput": false - } -} -*/ - -// PolicyPayload is the unmarshalled version of the payload envelope -type PolicyPayload struct { - FeePayload // Inherit the same structure as the fee payload - Callbacks []*PolicyCallback `json:"callbacks"` // IP addresses of double-spend notification servers such as mAPI reference implementation - Policies *Policy `json:"policies"` // values of miner policies as configured by the mAPI reference implementation administrator -} - -// ScriptFlag is a flag used in the policy quote -type ScriptFlag string - -// All known script flags -const ( - FlagCleanStack ScriptFlag = "CLEANSTACK" - FlagDerSig ScriptFlag = "DERSIG" - FlagDiscourageUpgradableNops ScriptFlag = "DISCOURAGE_UPGRADABLE_NOPS" - FlagMinimalData ScriptFlag = "MINIMALDATA" - FlagNullDummy ScriptFlag = "NULLDUMMY" -) - -// Policy is the struct of a policy (from policy quote response) -type Policy struct { - AcceptNonStdOutputs bool `json:"acceptnonstdoutputs"` - DataCarrier bool `json:"datacarrier"` - DataCarrierSize uint32 `json:"datacarriersize"` - LimitAncestorCount uint32 `json:"limitancestorcount"` - LimitCpfpGroupMembersCount uint32 `json:"limitcpfpgroupmemberscount"` - MaxNonStdTxValidationDuration uint32 `json:"maxnonstdtxvalidationduration"` - MaxScriptNumLengthPolicy uint32 `json:"maxscriptnumlengthpolicy"` - MaxScriptSizePolicy uint32 `json:"maxscriptsizepolicy"` - MaxStackMemoryUsagePolicy uint64 `json:"maxstackmemoryusagepolicy"` - MaxStdTxValidationDuration uint32 `json:"maxstdtxvalidationduration"` - MaxTxSizePolicy uint32 `json:"maxtxsizepolicy"` - SkipScriptFlags []ScriptFlag `json:"skipscriptflags"` - MaxConsolidationFactor uint32 `json:"minconsolidationfactor"` - MaxConsolidationInputScriptSize uint32 `json:"maxconsolidationinputscriptsize"` - MinConfConsolidationInput uint32 `json:"minconfconsolidationinput"` - AcceptNonStdConsolidationInput bool `json:"acceptnonstdconsolidationinput"` -} - -// PolicyCallback is the callback address -type PolicyCallback struct { - IPAddress string `json:"ipAddress"` + Quote *mapi.PolicyPayload `json:"quote"` // Custom field for unmarshalled payload data } // PolicyQuote will fire a Merchant API request to retrieve the policy from a given miner @@ -189,8 +81,8 @@ func (i *internalResult) parsePolicyQuote() (response PolicyQuoteResponse, err e if response.Quote != nil && len(response.Quote.Fees) > 0 && len(response.Quote.Fees[0].FeeType) == 0 { // This is an issue because go-bt json field is stripping the types - response.Quote.Fees[0].FeeType = FeeTypeStandard - response.Quote.Fees[1].FeeType = FeeTypeData + response.Quote.Fees[0].FeeType = mapi.FeeTypeStandard + response.Quote.Fees[1].FeeType = mapi.FeeTypeData } } return