-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: moves models to specific directories
- Loading branch information
Showing
9 changed files
with
305 additions
and
292 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.