diff --git a/monero/client/tx.go b/monero/client/tx.go new file mode 100644 index 0000000..fe1000a --- /dev/null +++ b/monero/client/tx.go @@ -0,0 +1,105 @@ +package client + +import ( + "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/mempool" + "git.gammaspectra.live/P2Pool/consensus/v3/types" + "git.gammaspectra.live/P2Pool/go-monero/pkg/rpc/daemon" +) + +func isRctBulletproof(t int) bool { + switch t { + case 3, 4, 5: // RCTTypeBulletproof, RCTTypeBulletproof2, RCTTypeCLSAG: + return true + default: + return false + } +} + +func isRctBulletproofPlus(t int) bool { + switch t { + case 6: // RCTTypeBulletproofPlus: + return true + default: + return false + } +} + +// NewEntryFromRPCData TODO +func NewEntryFromRPCData(id types.Hash, buf []byte, json *daemon.TransactionJSON) *mempool.MempoolEntry { + isBulletproof := isRctBulletproof(json.RctSignatures.Type) + isBulletproofPlus := isRctBulletproofPlus(json.RctSignatures.Type) + + var weight, paddedOutputs, bpBase, bpSize, bpClawback uint64 + if !isBulletproof && !isBulletproofPlus { + weight = uint64(len(buf)) + } else if isBulletproofPlus { + for _, proof := range json.RctsigPrunable.Bpp { + LSize := len(proof.L) / 2 + n2 := uint64(1 << (LSize - 6)) + if n2 == 0 { + paddedOutputs = 0 + break + } + paddedOutputs += n2 + } + { + + bpBase = uint64(32*6+7*2) / 2 + + //get_transaction_weight_clawback + if len(json.RctSignatures.Outpk) <= 2 { + bpClawback = 0 + } else { + nlr := 0 + for (1 << nlr) < paddedOutputs { + nlr++ + } + nlr += 6 + + bpSize = uint64(32*6 + 2*nlr) + + bpClawback = (bpBase*paddedOutputs - bpSize) * 4 / 5 + } + } + + weight = uint64(len(buf)) + bpClawback + } else { + for _, proof := range json.RctsigPrunable.Bp { + LSize := len(proof.L) / 2 + n2 := uint64(1 << (LSize - 6)) + if n2 == 0 { + paddedOutputs = 0 + break + } + paddedOutputs += n2 + } + { + + bpBase = uint64(32*9+7*2) / 2 + + //get_transaction_weight_clawback + if len(json.RctSignatures.Outpk) <= 2 { + bpClawback = 0 + } else { + nlr := 0 + for (1 << nlr) < paddedOutputs { + nlr++ + } + nlr += 6 + + bpSize = uint64(32*9 + 2*nlr) + + bpClawback = (bpBase*paddedOutputs - bpSize) * 4 / 5 + } + } + + weight = uint64(len(buf)) + bpClawback + } + + return &mempool.MempoolEntry{ + Id: id, + BlobSize: uint64(len(buf)), + Weight: weight, + Fee: json.RctSignatures.Txnfee, + } +} diff --git a/monero/client/zmq/types.go b/monero/client/zmq/types.go index 638a3dc..783b79c 100644 --- a/monero/client/zmq/types.go +++ b/monero/client/zmq/types.go @@ -2,6 +2,7 @@ package zmq import ( "git.gammaspectra.live/P2Pool/consensus/v3/monero/crypto" + "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/mempool" "git.gammaspectra.live/P2Pool/consensus/v3/types" ) @@ -25,6 +26,17 @@ type MinimalChainMain struct { Ids []types.Hash `json:"ids"` } +type TxOutput struct { + Amount uint64 `json:"amount"` + ToKey *struct { + Key crypto.PublicKeyBytes `json:"key"` + } `json:"to_key,omitempty"` + ToTaggedKey *struct { + Key crypto.PublicKeyBytes `json:"key"` + ViewTag string `json:"view_tag"` + } `json:"to_tagged_key,omitempty"` +} + type FullChainMain struct { MajorVersion int `json:"major_version"` MinorVersion int `json:"minor_version"` @@ -39,16 +51,7 @@ type FullChainMain struct { Height uint64 `json:"height"` } `json:"gen"` } `json:"inputs"` - Outputs []struct { - Amount uint64 `json:"amount"` - ToKey *struct { - Key crypto.PublicKeyBytes `json:"key"` - } `json:"to_key"` - ToTaggedKey *struct { - Key crypto.PublicKeyBytes `json:"key"` - ViewTag string `json:"view_tag"` - } `json:"to_tagged_key"` - } `json:"outputs"` + Outputs []TxOutput `json:"outputs"` Extra string `json:"extra"` Signatures []interface{} `json:"signatures"` Ringct struct { @@ -71,12 +74,7 @@ type FullTxPoolAdd struct { KeyImage types.Hash `json:"key_image"` } `json:"to_key"` } `json:"inputs"` - Outputs []struct { - Amount int `json:"amount"` - ToKey struct { - Key crypto.PublicKeyBytes `json:"key"` - } `json:"to_key"` - } `json:"outputs"` + Outputs []TxOutput `json:"outputs"` Extra string `json:"extra"` Signatures []interface{} `json:"signatures"` Ringct struct { @@ -88,7 +86,7 @@ type FullTxPoolAdd struct { Commitments []string `json:"commitments"` Fee int `json:"fee"` Prunable struct { - RangeProofs []interface{} `json:"range_proofs"` + RangeProofs []any `json:"range_proofs"` Bulletproofs []struct { V []string `json:"V"` AUpper string `json:"A"` @@ -109,21 +107,14 @@ type FullTxPoolAdd struct { } `json:"ringct"` } -type TxMempoolData struct { - Id types.Hash `json:"id"` - BlobSize uint64 `json:"blob_size"` - Weight uint64 `json:"weight"` - Fee uint64 `json:"fee"` -} - type FullMinerData struct { - MajorVersion uint8 `json:"major_version"` - Height uint64 `json:"height"` - PrevId types.Hash `json:"prev_id"` - SeedHash types.Hash `json:"seed_hash"` - Difficulty types.Difficulty `json:"difficulty"` - MedianWeight uint64 `json:"median_weight"` - AlreadyGeneratedCoins uint64 `json:"already_generated_coins"` - MedianTimestamp uint64 `json:"median_timestamp"` - TxBacklog []TxMempoolData `json:"tx_backlog"` + MajorVersion uint8 `json:"major_version"` + Height uint64 `json:"height"` + PrevId types.Hash `json:"prev_id"` + SeedHash types.Hash `json:"seed_hash"` + Difficulty types.Difficulty `json:"difficulty"` + MedianWeight uint64 `json:"median_weight"` + AlreadyGeneratedCoins uint64 `json:"already_generated_coins"` + MedianTimestamp uint64 `json:"median_timestamp"` + TxBacklog []*mempool.MempoolEntry `json:"tx_backlog"` } diff --git a/monero/client/zmq/zmq.go b/monero/client/zmq/zmq.go index 13b261b..992b905 100644 --- a/monero/client/zmq/zmq.go +++ b/monero/client/zmq/zmq.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/mempool" "git.gammaspectra.live/P2Pool/consensus/v3/utils" "slices" "strings" @@ -42,11 +43,11 @@ type Stream struct { FullTxPoolAddC func([]FullTxPoolAdd) FullMinerDataC func(*FullMinerData) MinimalChainMainC func(*MinimalChainMain) - MinimalTxPoolAddC func([]TxMempoolData) + MinimalTxPoolAddC func(mempool.Mempool) } // Listen listens for a list of topics pre-configured for this client (via NewClient). -func (c *Client) Listen(ctx context.Context, fullChainMain func(chainMain *FullChainMain), fullTxPoolAdd func(txs []FullTxPoolAdd), fullMinerData func(main *FullMinerData), minimalChainMain func(chainMain *MinimalChainMain), minimalTxPoolAdd func(txs []TxMempoolData)) error { +func (c *Client) Listen(ctx context.Context, fullChainMain func(chainMain *FullChainMain), fullTxPoolAdd func(txs []FullTxPoolAdd), fullMinerData func(main *FullMinerData), minimalChainMain func(chainMain *MinimalChainMain), minimalTxPoolAdd func(txs mempool.Mempool)) error { if err := c.listen(ctx, c.topics...); err != nil { return fmt.Errorf("listen on '%s': %w", strings.Join(func() (r []string) { for _, s := range c.topics { @@ -191,7 +192,7 @@ func (c *Client) transmitMinimalChainMain(stream *Stream, gson []byte) error { } func (c *Client) transmitMinimalTxPoolAdd(stream *Stream, gson []byte) error { - var arr []TxMempoolData + var arr mempool.Mempool if err := utils.UnmarshalJSON(gson, &arr); err != nil { return fmt.Errorf("unmarshal: %w", err) diff --git a/monero/client/zmq/zmq_test.go b/monero/client/zmq/zmq_test.go index 972e20e..35b0fea 100644 --- a/monero/client/zmq/zmq_test.go +++ b/monero/client/zmq/zmq_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "git.gammaspectra.live/P2Pool/consensus/v3/monero/client/zmq" + "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/mempool" "os" "testing" "time" @@ -78,7 +79,7 @@ func TestClient(t *testing.T) { t.Log(main) }, func(chainMain *zmq.MinimalChainMain) { t.Log(chainMain) - }, func(txs []zmq.TxMempoolData) { + }, func(txs mempool.Mempool) { t.Log(txs) }) diff --git a/p2pool/mainchain/mainchain.go b/p2pool/mainchain/mainchain.go index b84cdeb..eca0672 100644 --- a/p2pool/mainchain/mainchain.go +++ b/p2pool/mainchain/mainchain.go @@ -139,18 +139,9 @@ func (c *MainChain) Listen() error { TransactionParentIndices: nil, } c.HandleMainBlock(blockData) - }, func(txs []zmq.FullTxPoolAdd) { - - }, func(fullMinerData *zmq.FullMinerData) { - pool := make(mempool.Mempool, len(fullMinerData.TxBacklog)) - for i := range fullMinerData.TxBacklog { - pool[i] = &mempool.MempoolEntry{ - Id: fullMinerData.TxBacklog[i].Id, - BlobSize: fullMinerData.TxBacklog[i].BlobSize, - Weight: fullMinerData.TxBacklog[i].Weight, - Fee: fullMinerData.TxBacklog[i].Fee, - } - } + }, + func(txs []zmq.FullTxPoolAdd) {}, + func(fullMinerData *zmq.FullMinerData) { c.HandleMinerData(&p2pooltypes.MinerData{ MajorVersion: fullMinerData.MajorVersion, Height: fullMinerData.Height, @@ -160,23 +151,13 @@ func (c *MainChain) Listen() error { MedianWeight: fullMinerData.MedianWeight, AlreadyGeneratedCoins: fullMinerData.AlreadyGeneratedCoins, MedianTimestamp: fullMinerData.MedianTimestamp, - TxBacklog: pool, + TxBacklog: fullMinerData.TxBacklog, TimeReceived: time.Now(), }) - }, func(chainMain *zmq.MinimalChainMain) { - - }, func(txs []zmq.TxMempoolData) { - m := make(mempool.Mempool, len(txs)) - for i := range txs { - m[i] = &mempool.MempoolEntry{ - Id: txs[i].Id, - BlobSize: txs[i].BlobSize, - Weight: txs[i].Weight, - Fee: txs[i].Fee, - } - } - c.p2pool.UpdateMempoolData(m) - }) + }, + func(chainMain *zmq.MinimalChainMain) {}, + c.p2pool.UpdateMempoolData, + ) if err != nil { return err } diff --git a/p2pool/mempool/mempool.go b/p2pool/mempool/mempool.go index bad0952..e7ada66 100644 --- a/p2pool/mempool/mempool.go +++ b/p2pool/mempool/mempool.go @@ -3,7 +3,6 @@ package mempool import ( "git.gammaspectra.live/P2Pool/consensus/v3/types" "git.gammaspectra.live/P2Pool/consensus/v3/utils" - "git.gammaspectra.live/P2Pool/go-monero/pkg/rpc/daemon" "lukechampine.com/uint128" "math" "math/bits" @@ -11,10 +10,10 @@ import ( ) type MempoolEntry struct { - Id types.Hash - BlobSize uint64 - Weight uint64 - Fee uint64 + Id types.Hash `json:"id"` + BlobSize uint64 `json:"blob_size"` + Weight uint64 `json:"weight"` + Fee uint64 `json:"fee"` } type Mempool []*MempoolEntry @@ -185,100 +184,3 @@ func GetBlockReward(baseReward, medianWeight, fees, weight uint64) uint64 { return reward + fees } - -func isRctBulletproof(t int) bool { - switch t { - case 3, 4, 5: // RCTTypeBulletproof, RCTTypeBulletproof2, RCTTypeCLSAG: - return true - default: - return false - } -} - -func isRctBulletproofPlus(t int) bool { - switch t { - case 6: // RCTTypeBulletproofPlus: - return true - default: - return false - } -} - -func NewEntryFromRPCData(id types.Hash, buf []byte, json *daemon.TransactionJSON) *MempoolEntry { - isBulletproof := isRctBulletproof(json.RctSignatures.Type) - isBulletproofPlus := isRctBulletproofPlus(json.RctSignatures.Type) - - var weight, paddedOutputs, bpBase, bpSize, bpClawback uint64 - if !isBulletproof && !isBulletproofPlus { - weight = uint64(len(buf)) - } else if isBulletproofPlus { - for _, proof := range json.RctsigPrunable.Bpp { - LSize := len(proof.L) / 2 - n2 := uint64(1 << (LSize - 6)) - if n2 == 0 { - paddedOutputs = 0 - break - } - paddedOutputs += n2 - } - { - - bpBase = uint64(32*6+7*2) / 2 - - //get_transaction_weight_clawback - if len(json.RctSignatures.Outpk) <= 2 { - bpClawback = 0 - } else { - nlr := 0 - for (1 << nlr) < paddedOutputs { - nlr++ - } - nlr += 6 - - bpSize = uint64(32*6 + 2*nlr) - - bpClawback = (bpBase*paddedOutputs - bpSize) * 4 / 5 - } - } - - weight = uint64(len(buf)) + bpClawback - } else { - for _, proof := range json.RctsigPrunable.Bp { - LSize := len(proof.L) / 2 - n2 := uint64(1 << (LSize - 6)) - if n2 == 0 { - paddedOutputs = 0 - break - } - paddedOutputs += n2 - } - { - - bpBase = uint64(32*9+7*2) / 2 - - //get_transaction_weight_clawback - if len(json.RctSignatures.Outpk) <= 2 { - bpClawback = 0 - } else { - nlr := 0 - for (1 << nlr) < paddedOutputs { - nlr++ - } - nlr += 6 - - bpSize = uint64(32*9 + 2*nlr) - - bpClawback = (bpBase*paddedOutputs - bpSize) * 4 / 5 - } - } - - weight = uint64(len(buf)) + bpClawback - } - - return &MempoolEntry{ - Id: id, - BlobSize: uint64(len(buf)), - Weight: weight, - Fee: json.RctSignatures.Txnfee, - } -}