diff --git a/pkg/super_node/btc/converter.go b/pkg/super_node/btc/converter.go new file mode 100644 index 00000000..0a1bba07 --- /dev/null +++ b/pkg/super_node/btc/converter.go @@ -0,0 +1,69 @@ +// VulcanizeDB +// Copyright © 2019 Vulcanize + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package btc + +import ( + "bytes" + "fmt" + + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" +) + +// PayloadConverter satisfies the PayloadConverter interface for bitcoin +type PayloadConverter struct{} + +// NewPayloadConverter creates a pointer to a new PayloadConverter which satisfies the PayloadConverter interface +func NewPayloadConverter() *PayloadConverter { + return &PayloadConverter{} +} + +// Convert method is used to convert a bitcoin BlockPayload to an IPLDPayload +// Satisfies the shared.PayloadConverter interface +func (pc *PayloadConverter) Convert(payload interface{}) (interface{}, error) { + btcBlockPayload, ok := payload.(BlockPayload) + if !ok { + return nil, fmt.Errorf("btc converter: expected payload type %T got %T", BlockPayload{}, payload) + } + msgBlock := wire.NewMsgBlock(btcBlockPayload.Header) + for _, tx := range btcBlockPayload.Txs { + msgBlock.AddTransaction(tx.MsgTx()) + } + w := bytes.NewBuffer(make([]byte, 0, msgBlock.SerializeSize())) + if err := msgBlock.Serialize(w); err != nil { + return nil, err + } + utilBlock := btcutil.NewBlockFromBlockAndBytes(msgBlock, w.Bytes()) + utilBlock.SetHeight(btcBlockPayload.Height) + txMeta := make([]TxModel, len(btcBlockPayload.Txs)) + for _, tx := range utilBlock.Transactions() { + index := tx.Index() + txModel := TxModel{ + TxHash: tx.Hash().String(), + Index: int64(tx.Index()), + HasWitness: tx.HasWitness(), + } + if tx.HasWitness() { + txModel.WitnessHash = tx.WitnessHash().String() + } + txMeta[index] = txModel + } + return IPLDPayload{ + Block: utilBlock, + TxMetaData: txMeta, + }, nil +} diff --git a/pkg/super_node/btc/types.go b/pkg/super_node/btc/types.go index 5ff9df42..77cb3eae 100644 --- a/pkg/super_node/btc/types.go +++ b/pkg/super_node/btc/types.go @@ -12,13 +12,18 @@ // GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . +// along with this program. If not, see . package btc import ( + "encoding/json" + "math/big" + "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" + "github.com/ethereum/go-ethereum/common" + "github.com/ipfs/go-block-format" ) // BlockPayload packages the block and tx data received from block connection notifications @@ -26,4 +31,75 @@ type BlockPayload struct { Height int32 Header *wire.BlockHeader Txs []*btcutil.Tx -} \ No newline at end of file +} + +// IPLDPayload is a custom type which packages raw BTC data for publishing to IPFS and filtering to subscribers +// Returned by PayloadConverter +// Passed to IPLDPublisher and ResponseFilterer +type IPLDPayload struct { + Block *btcutil.Block + TxMetaData []TxModel +} + +// Trie struct used to flag node as leaf or not +type TrieNode struct { + Key common.Hash + Value []byte + Leaf bool +} + +// CIDPayload is a struct to hold all the CIDs and their associated meta data for indexing in Postgres +// Returned by IPLDPublisher +// Passed to CIDIndexer +type CIDPayload struct { + HeaderCID HeaderModel + TransactionCIDs []TxModel +} + +// CIDWrapper is used to direct fetching of IPLDs from IPFS +// Returned by CIDRetriever +// Passed to IPLDFetcher +type CIDWrapper struct { + BlockNumber *big.Int + Headers []HeaderModel + Transactions []TxModel +} + +// IPLDWrapper is used to package raw IPLD block data fetched from IPFS +// Returned by IPLDFetcher +// Passed to IPLDResolver +type IPLDWrapper struct { + BlockNumber *big.Int + Headers []blocks.Block + Transactions []blocks.Block +} + +// StreamPayload holds the data streamed from the super node eth service to the requesting clients +// Returned by IPLDResolver and ResponseFilterer +// Passed to client subscriptions +type StreamPayload struct { + BlockNumber *big.Int `json:"blockNumber"` + HeadersBytes [][]byte `json:"headerBytes"` + TransactionsBytes [][]byte `json:"transactionBytes"` + + encoded []byte + err error +} + +func (sd *StreamPayload) ensureEncoded() { + if sd.encoded == nil && sd.err == nil { + sd.encoded, sd.err = json.Marshal(sd) + } +} + +// Length to implement Encoder interface for StateDiff +func (sd *StreamPayload) Length() int { + sd.ensureEncoded() + return len(sd.encoded) +} + +// Encode to implement Encoder interface for StateDiff +func (sd *StreamPayload) Encode() ([]byte, error) { + sd.ensureEncoded() + return sd.encoded, sd.err +} diff --git a/pkg/super_node/constructors.go b/pkg/super_node/constructors.go index f961b88c..09473c13 100644 --- a/pkg/super_node/constructors.go +++ b/pkg/super_node/constructors.go @@ -18,6 +18,7 @@ package super_node import ( "fmt" + "github.com/btcsuite/btcd/rpcclient" "github.com/vulcanize/vulcanizedb/pkg/super_node/btc" @@ -109,6 +110,8 @@ func NewPayloadConverter(chain config.ChainType, settings interface{}) (shared.P return nil, fmt.Errorf("ethereum converter constructor expected config type %T got %T", ¶ms.ChainConfig{}, settings) } return eth.NewPayloadConverter(ethConfig), nil + case config.Bitcoin: + return btc.NewPayloadConverter(), nil default: return nil, fmt.Errorf("invalid chain %T for converter constructor", chain) }