Skip to content

Commit

Permalink
feat: current progress
Browse files Browse the repository at this point in the history
  • Loading branch information
wregulski committed Jun 1, 2023
1 parent 969b04a commit 3f7e6ad
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 38 deletions.
8 changes: 8 additions & 0 deletions apis/arc/fee_quote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package arc

import "github.com/libsv/go-bt/v2"

// FeePayload is the unmarshalled version of the payload envelope
type FeePayload struct {
Fees *bt.Fee `json:"fees"`
}
15 changes: 15 additions & 0 deletions apis/arc/policy_quote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package arc

import "github.com/libsv/go-bt/v2"

type Policy struct {
MaxScriptSizePolicy uint32 `json:"maxscriptsizepolicy"`
MaxTxSigOpsCount uint32 `json:"maxtxsigopscount"`
MaxTxSizePolicy uint32 `json:"maxtxsizepolicy"`
MiningFee *bt.Fee `json:"miningFee"`
}

type PolicyQuoteModel struct {
Policy Policy `json:"policy"`
Timestamp string `json:"timestamp"`
}
4 changes: 2 additions & 2 deletions apis/mapi/fee_quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ type (
RawFeePayload struct {
FeePayloadFields
Callbacks []*PolicyCallback `json:"callbacks"` // IP addresses of double-spend notification servers such as mAPI reference implementation
Fees []*feeObj `json:"fees"`
Fees []*FeeObj `json:"fees"`
}

// feePayloadFields are the same fields in both payloads
Expand All @@ -108,7 +108,7 @@ type (
// 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 {
FeeObj struct {
FeeType string `json:"feeType"` // standard || data
MiningFee FeeUnit `json:"miningFee"`
RelayFee FeeUnit `json:"relayFee"` // Fee for retaining Tx in secondary mempool
Expand Down
56 changes: 36 additions & 20 deletions apis/mapi/policy_quote.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package mapi

/*
Example policyQuote response from Merchant API:
{
"payload": "{\"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,\"dustrelayfee\":150,\"maxstdtxvalidationduration\":99,\"maxnonstdtxvalidationduration\":100,\"dustlimitfactor\":10}}",
"signature": "30440220708e2e62a393f53c43d172bc1459b4daccf9cf23ff77cff923f09b2b49b94e0a022033792bee7bc3952f4b1bfbe9df6407086b5dbfc161df34fdee684dc97be72731",
"publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
"encoding": "UTF-8",
"mimetype": "application/json"
}
*/

/*
Example PolicyQuoteResponse.Payload (unmarshalled):
Expand Down Expand Up @@ -66,26 +78,6 @@ Example PolicyQuoteResponse.Payload (unmarshalled):
}
*/

// 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"`
Expand All @@ -105,6 +97,30 @@ type Policy struct {
AcceptNonStdConsolidationInput bool `json:"acceptnonstdconsolidationinput"`
}

type PolicyQuoteModel struct {
APIVersion string `json:"apiVersion"`
Timestamp string `json:"timestamp"`
ExpiryTime string `json:"expiryTime"`
MinerID string `json:"minerId"`
CurrentHighestBlockHash string `json:"currentHighestBlockHash"`
CurrentHighestBlockHeight uint64 `json:"currentHighestBlockHeight"`
Fees []FeeObj `json:"fees"`
Callbacks []PolicyCallback `json:"callbacks"`
Policies Policy `json:"policies"`
}

// 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"
)

// PolicyCallback is the callback address
type PolicyCallback struct {
IPAddress string `json:"ipAddress"`
Expand Down
61 changes: 49 additions & 12 deletions policy_quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,66 @@ import (
"encoding/json"
"errors"

"github.com/libsv/go-bt/v2"
"github.com/tonicpow/go-minercraft/apis/arc"
"github.com/tonicpow/go-minercraft/apis/mapi"
)

/*
Example policyQuote response from Merchant API:
type PolicyQuoteModelAdapter interface {
GetPolicyData() *PolicyPayload
}

type PolicyQuoteMapiAdapter struct {
*mapi.PolicyQuoteModel
}

type PolicyQuoteArcAdapter struct {
*arc.PolicyQuoteModel
}

type UnifiedPolicy 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 []mapi.ScriptFlag `json:"skipscriptflags"`
MaxConsolidationFactor uint32 `json:"minconsolidationfactor"`
MaxConsolidationInputScriptSize uint32 `json:"maxconsolidationinputscriptsize"`
MinConfConsolidationInput uint32 `json:"minconfconsolidationinput"`
AcceptNonStdConsolidationInput bool `json:"acceptnonstdconsolidationinput"`

// Additional fields for Policy in API2
MaxTxSigOpsCount uint32 `json:"maxtxsigopscount"`
}

type UnifiedFeePayload struct {
mapi.FeePayloadFields
Fees []*bt.Fee `json:"fees"`
}

{
"payload": "{\"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,\"dustrelayfee\":150,\"maxstdtxvalidationduration\":99,\"maxnonstdtxvalidationduration\":100,\"dustlimitfactor\":10}}",
"signature": "30440220708e2e62a393f53c43d172bc1459b4daccf9cf23ff77cff923f09b2b49b94e0a022033792bee7bc3952f4b1bfbe9df6407086b5dbfc161df34fdee684dc97be72731",
"publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
"encoding": "UTF-8",
"mimetype": "application/json"
// PolicyPayload is the unmarshalled version of the payload envelope
type PolicyPayload struct {
UnifiedFeePayload // Inherit the same structure as the fee payload
Callbacks []*mapi.PolicyCallback `json:"callbacks"` // IP addresses of double-spend notification servers such as mAPI reference implementation
Policies *UnifiedPolicy `json:"policies"` // values of miner policies as configured by the mAPI reference implementation administrator
}
*/

// PolicyQuoteResponse is the raw response from the Merchant API request
// PolicyQuoteResponse is the raw response from the API request
//
// Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi#1-get-policy-quote
type PolicyQuoteResponse struct {
JSONEnvelope
Quote *mapi.PolicyPayload `json:"quote"` // Custom field for unmarshalled payload data
Quote *PolicyPayload `json:"quote"` // Custom field for unmarshalled payload data
}

// PolicyQuote will fire a Merchant API request to retrieve the policy from a given miner
// PolicyQuote will fire a Merchant&Arc API request to retrieve the policy from a given miner
//
// This endpoint is used to get the different policies quoted by a miner.
// It returns a JSONEnvelope with a payload that contains the policies used by a specific BSV miner.
Expand All @@ -37,6 +73,7 @@ type PolicyQuoteResponse struct {
// includes information on DSNT IP addresses and miner policies.
//
// Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi#1-get-policy-quote
// Specs: https://docs.gorillapool.io/arc/api.html#get-the-policy-settings
func (c *Client) PolicyQuote(ctx context.Context, miner *Miner) (*PolicyQuoteResponse, error) {

// Make sure we have a valid miner
Expand Down
31 changes: 27 additions & 4 deletions submit_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
)

const (
Expand Down Expand Up @@ -185,12 +187,33 @@ func submitTransaction(ctx context.Context, client *Client, miner *Miner, tx *Tr
if err != nil {
return nil, fmt.Errorf("failed to marshall JSON when submitting transaction %w", err)
}

sb := strings.Builder{}

api, err := MinerAPIByMinerID(client.minerAPIs, miner.MinerID, client.apiType)
if err != nil {
result.Response = &RequestResponse{Error: err}
return nil, err
}

route, err := ActionRouteByAPIType(SubmitTx, client.apiType)
if err != nil {
result.Response = &RequestResponse{Error: err}
return nil, err
}

sb.WriteString(api.URL + route)
submitURL, err := url.Parse(sb.String())
if err != nil {
result.Response = &RequestResponse{Error: err}
return nil, err
}

result.Response = httpRequest(ctx, client, &httpPayload{
Method: http.MethodPost,
// TODO: Align with new structure
// URL: miner.URL + routeSubmitTx,
// Token: miner.Token,
Data: data,
URL: submitURL.String(),
Token: api.Token,
Data: data,
})
return result, nil
}

0 comments on commit 3f7e6ad

Please sign in to comment.