Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //HAIRCOMB DOWNLOADER
- package main
- import "crypto/aes"
- import "crypto/sha256"
- import (
- "bytes"
- "io"
- "time"
- )
- import (
- "crypto/rand"
- "encoding/binary"
- "fmt"
- "math"
- )
- import "net"
- import "sync"
- import "log"
- import (
- "encoding/hex"
- )
- import "os"
- import (
- "unicode/utf8"
- )
- import (
- "errors"
- )
- import "os/signal"
- import "syscall"
- import (
- "strconv"
- )
- import (
- "strings"
- )
- func aes_checksum(buf, load_aes *[32]byte) {
- var aestmp [32]byte
- var aes, err5 = aes.NewCipher(buf[0:])
- if err5 != nil {
- panic("cannot use aes")
- }
- aes.Encrypt(aestmp[0:16], load_aes[0:16])
- aes.Decrypt(aestmp[16:32], load_aes[16:32])
- for i := 8; i < 16; i++ {
- aestmp[i], aestmp[8+i] = aestmp[8+i], aestmp[i]
- }
- aes.Encrypt(load_aes[0:16], aestmp[0:16])
- aes.Decrypt(load_aes[16:32], aestmp[16:32])
- }
- func BCDFromUint(value uint64, buf []byte) {
- if value > 0 {
- remainder := value
- for pos := len(buf) - 1; pos >= 0 && remainder > 0; pos-- {
- tail := byte(remainder % 100)
- hi, lo := tail/10, tail%10
- buf[pos] = byte(hi<<4 + lo)
- remainder = remainder / 100
- }
- }
- }
- const MaxBlockHeaderPayload = 16 + (HashSize * 2)
- type BlockHeader struct {
- Version int32
- PrevBlock Hash
- MerkleRoot Hash
- Timestamp time.Time
- Bits uint32
- Nonce uint32
- }
- const blockHeaderLen = 80
- func (h *BlockHeader) BlockHash() Hash {
- buf := bytes.NewBuffer(make([]byte, 0, MaxBlockHeaderPayload))
- _ = writeBlockHeader(buf, 0, h)
- return DoubleHashH(buf.Bytes())
- }
- func (h *BlockHeader) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- return readBlockHeader(r, pver, h)
- }
- func (h *BlockHeader) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- return writeBlockHeader(w, pver, h)
- }
- func (h *BlockHeader) Deserialize(r io.Reader) error {
- return readBlockHeader(r, 0, h)
- }
- func (h *BlockHeader) Serialize(w io.Writer) error {
- return writeBlockHeader(w, 0, h)
- }
- func NewBlockHeader(version int32, prevHash, merkleRootHash *Hash,
- bits uint32, nonce uint32) *BlockHeader {
- return &BlockHeader{
- Version: version,
- PrevBlock: *prevHash,
- MerkleRoot: *merkleRootHash,
- Timestamp: time.Unix(time.Now().Unix(), 0),
- Bits: bits,
- Nonce: nonce,
- }
- }
- func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
- return readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
- (*uint32Time)(&bh.Timestamp), &bh.Bits, &bh.Nonce)
- }
- func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
- sec := uint32(bh.Timestamp.Unix())
- return writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
- sec, bh.Bits, bh.Nonce)
- }
- const (
- MaxVarIntPayload = 9
- binaryFreeListMaxItems = 1024
- )
- var (
- littleEndian = binary.LittleEndian
- bigEndian = binary.BigEndian
- )
- type binaryFreeList chan []byte
- func (l binaryFreeList) Borrow() []byte {
- var buf []byte
- select {
- case buf = <-l:
- default:
- buf = make([]byte, 8)
- }
- return buf[:8]
- }
- func (l binaryFreeList) Return(buf []byte) {
- select {
- case l <- buf:
- default:
- }
- }
- func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
- buf := l.Borrow()[:1]
- if _, err := io.ReadFull(r, buf); err != nil {
- l.Return(buf)
- return 0, err
- }
- rv := buf[0]
- l.Return(buf)
- return rv, nil
- }
- func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) {
- buf := l.Borrow()[:2]
- if _, err := io.ReadFull(r, buf); err != nil {
- l.Return(buf)
- return 0, err
- }
- rv := byteOrder.Uint16(buf)
- l.Return(buf)
- return rv, nil
- }
- func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
- buf := l.Borrow()[:4]
- if _, err := io.ReadFull(r, buf); err != nil {
- l.Return(buf)
- return 0, err
- }
- rv := byteOrder.Uint32(buf)
- l.Return(buf)
- return rv, nil
- }
- func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) {
- buf := l.Borrow()[:8]
- if _, err := io.ReadFull(r, buf); err != nil {
- l.Return(buf)
- return 0, err
- }
- rv := byteOrder.Uint64(buf)
- l.Return(buf)
- return rv, nil
- }
- func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
- buf := l.Borrow()[:1]
- buf[0] = val
- _, err := w.Write(buf)
- l.Return(buf)
- return err
- }
- func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error {
- buf := l.Borrow()[:2]
- byteOrder.PutUint16(buf, val)
- _, err := w.Write(buf)
- l.Return(buf)
- return err
- }
- func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error {
- buf := l.Borrow()[:4]
- byteOrder.PutUint32(buf, val)
- _, err := w.Write(buf)
- l.Return(buf)
- return err
- }
- func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error {
- buf := l.Borrow()[:8]
- byteOrder.PutUint64(buf, val)
- _, err := w.Write(buf)
- l.Return(buf)
- return err
- }
- var binarySerializer binaryFreeList = make(chan []byte, binaryFreeListMaxItems)
- var errNonCanonicalVarInt = "non-canonical varint %x - discriminant %x must " +
- "encode a value greater than %x"
- type uint32Time time.Time
- type int64Time time.Time
- func readElement(r io.Reader, element interface{}) error {
- switch e := element.(type) {
- case *int32:
- rv, err := binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- return err
- }
- *e = int32(rv)
- return nil
- case *uint32:
- rv, err := binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- return err
- }
- *e = rv
- return nil
- case *int64:
- rv, err := binarySerializer.Uint64(r, littleEndian)
- if err != nil {
- return err
- }
- *e = int64(rv)
- return nil
- case *uint64:
- rv, err := binarySerializer.Uint64(r, littleEndian)
- if err != nil {
- return err
- }
- *e = rv
- return nil
- case *bool:
- rv, err := binarySerializer.Uint8(r)
- if err != nil {
- return err
- }
- if rv == 0x00 {
- *e = false
- } else {
- *e = true
- }
- return nil
- case *uint32Time:
- rv, err := binarySerializer.Uint32(r, binary.LittleEndian)
- if err != nil {
- return err
- }
- *e = uint32Time(time.Unix(int64(rv), 0))
- return nil
- case *int64Time:
- rv, err := binarySerializer.Uint64(r, binary.LittleEndian)
- if err != nil {
- return err
- }
- *e = int64Time(time.Unix(int64(rv), 0))
- return nil
- case *[4]byte:
- _, err := io.ReadFull(r, e[:])
- if err != nil {
- return err
- }
- return nil
- case *[CommandSize]uint8:
- _, err := io.ReadFull(r, e[:])
- if err != nil {
- return err
- }
- return nil
- case *[16]byte:
- _, err := io.ReadFull(r, e[:])
- if err != nil {
- return err
- }
- return nil
- case *Hash:
- _, err := io.ReadFull(r, e[:])
- if err != nil {
- return err
- }
- return nil
- case *ServiceFlag:
- rv, err := binarySerializer.Uint64(r, littleEndian)
- if err != nil {
- return err
- }
- *e = ServiceFlag(rv)
- return nil
- case *InvType:
- rv, err := binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- return err
- }
- *e = InvType(rv)
- return nil
- case *BitcoinNet:
- rv, err := binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- return err
- }
- *e = BitcoinNet(rv)
- return nil
- case *BloomUpdateType:
- rv, err := binarySerializer.Uint8(r)
- if err != nil {
- return err
- }
- *e = BloomUpdateType(rv)
- return nil
- case *RejectCode:
- rv, err := binarySerializer.Uint8(r)
- if err != nil {
- return err
- }
- *e = RejectCode(rv)
- return nil
- }
- return binary.Read(r, littleEndian, element)
- }
- func readElements(r io.Reader, elements ...interface{}) error {
- for _, element := range elements {
- err := readElement(r, element)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func writeElement(w io.Writer, element interface{}) error {
- switch e := element.(type) {
- case int32:
- err := binarySerializer.PutUint32(w, littleEndian, uint32(e))
- if err != nil {
- return err
- }
- return nil
- case uint32:
- err := binarySerializer.PutUint32(w, littleEndian, e)
- if err != nil {
- return err
- }
- return nil
- case int64:
- err := binarySerializer.PutUint64(w, littleEndian, uint64(e))
- if err != nil {
- return err
- }
- return nil
- case uint64:
- err := binarySerializer.PutUint64(w, littleEndian, e)
- if err != nil {
- return err
- }
- return nil
- case bool:
- var err error
- if e {
- err = binarySerializer.PutUint8(w, 0x01)
- } else {
- err = binarySerializer.PutUint8(w, 0x00)
- }
- if err != nil {
- return err
- }
- return nil
- case [4]byte:
- _, err := w.Write(e[:])
- if err != nil {
- return err
- }
- return nil
- case [CommandSize]uint8:
- _, err := w.Write(e[:])
- if err != nil {
- return err
- }
- return nil
- case [16]byte:
- _, err := w.Write(e[:])
- if err != nil {
- return err
- }
- return nil
- case *Hash:
- _, err := w.Write(e[:])
- if err != nil {
- return err
- }
- return nil
- case ServiceFlag:
- err := binarySerializer.PutUint64(w, littleEndian, uint64(e))
- if err != nil {
- return err
- }
- return nil
- case InvType:
- err := binarySerializer.PutUint32(w, littleEndian, uint32(e))
- if err != nil {
- return err
- }
- return nil
- case BitcoinNet:
- err := binarySerializer.PutUint32(w, littleEndian, uint32(e))
- if err != nil {
- return err
- }
- return nil
- case BloomUpdateType:
- err := binarySerializer.PutUint8(w, uint8(e))
- if err != nil {
- return err
- }
- return nil
- case RejectCode:
- err := binarySerializer.PutUint8(w, uint8(e))
- if err != nil {
- return err
- }
- return nil
- }
- return binary.Write(w, littleEndian, element)
- }
- func writeElements(w io.Writer, elements ...interface{}) error {
- for _, element := range elements {
- err := writeElement(w, element)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
- discriminant, err := binarySerializer.Uint8(r)
- if err != nil {
- return 0, err
- }
- var rv uint64
- switch discriminant {
- case 0xff:
- sv, err := binarySerializer.Uint64(r, littleEndian)
- if err != nil {
- return 0, err
- }
- rv = sv
- min := uint64(0x100000000)
- if rv < min {
- return 0, messageError("ReadVarInt", fmt.Sprintf(
- errNonCanonicalVarInt, rv, discriminant, min))
- }
- case 0xfe:
- sv, err := binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- return 0, err
- }
- rv = uint64(sv)
- min := uint64(0x10000)
- if rv < min {
- return 0, messageError("ReadVarInt", fmt.Sprintf(
- errNonCanonicalVarInt, rv, discriminant, min))
- }
- case 0xfd:
- sv, err := binarySerializer.Uint16(r, littleEndian)
- if err != nil {
- return 0, err
- }
- rv = uint64(sv)
- min := uint64(0xfd)
- if rv < min {
- return 0, messageError("ReadVarInt", fmt.Sprintf(
- errNonCanonicalVarInt, rv, discriminant, min))
- }
- default:
- rv = uint64(discriminant)
- }
- return rv, nil
- }
- func WriteVarInt(w io.Writer, pver uint32, val uint64) error {
- if val < 0xfd {
- return binarySerializer.PutUint8(w, uint8(val))
- }
- if val <= math.MaxUint16 {
- err := binarySerializer.PutUint8(w, 0xfd)
- if err != nil {
- return err
- }
- return binarySerializer.PutUint16(w, littleEndian, uint16(val))
- }
- if val <= math.MaxUint32 {
- err := binarySerializer.PutUint8(w, 0xfe)
- if err != nil {
- return err
- }
- return binarySerializer.PutUint32(w, littleEndian, uint32(val))
- }
- err := binarySerializer.PutUint8(w, 0xff)
- if err != nil {
- return err
- }
- return binarySerializer.PutUint64(w, littleEndian, val)
- }
- func VarIntSerializeSize(val uint64) int {
- if val < 0xfd {
- return 1
- }
- if val <= math.MaxUint16 {
- return 3
- }
- if val <= math.MaxUint32 {
- return 5
- }
- return 9
- }
- func ReadVarString(r io.Reader, pver uint32) (string, error) {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return "", err
- }
- if count > MaxMessagePayload {
- str := fmt.Sprintf("variable length string is too long "+
- "[count %d, max %d]", count, MaxMessagePayload)
- return "", messageError("ReadVarString", str)
- }
- buf := make([]byte, count)
- _, err = io.ReadFull(r, buf)
- if err != nil {
- return "", err
- }
- return string(buf), nil
- }
- func WriteVarString(w io.Writer, pver uint32, str string) error {
- err := WriteVarInt(w, pver, uint64(len(str)))
- if err != nil {
- return err
- }
- _, err = w.Write([]byte(str))
- return err
- }
- func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32,
- fieldName string) ([]byte, error) {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return nil, err
- }
- if count > uint64(maxAllowed) {
- str := fmt.Sprintf("%s is larger than the max allowed size "+
- "[count %d, max %d]", fieldName, count, maxAllowed)
- return nil, messageError("ReadVarBytes", str)
- }
- b := make([]byte, count)
- _, err = io.ReadFull(r, b)
- if err != nil {
- return nil, err
- }
- return b, nil
- }
- func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) error {
- slen := uint64(len(bytes))
- err := WriteVarInt(w, pver, slen)
- if err != nil {
- return err
- }
- _, err = w.Write(bytes)
- return err
- }
- func randomUint64(r io.Reader) (uint64, error) {
- rv, err := binarySerializer.Uint64(r, bigEndian)
- if err != nil {
- return 0, err
- }
- return rv, nil
- }
- func RandomUint64() (uint64, error) {
- return randomUint64(rand.Reader)
- }
- const max_cruisers = 64
- const extra_addresses = 1024
- var current_cruisers_mutex sync.Mutex
- var current_ended bool
- var current_all_cruisers map[string]*net.Conn
- var current_extra_cruisers map[string]struct{}
- func init() {
- current_all_cruisers = make(map[string]*net.Conn)
- current_extra_cruisers = make(map[string]struct{})
- }
- func cruiser_pending_extra_address() bool {
- current_cruisers_mutex.Lock()
- var pending = len(current_extra_cruisers) < extra_addresses
- current_cruisers_mutex.Unlock()
- return pending
- }
- func start_cruises(cru []string) {
- for _, str := range cru {
- go func() {
- if err := cruise(str); err != nil {
- fmt.Println(err)
- }
- }()
- }
- }
- func has_cruiser(addr string) bool {
- current_cruisers_mutex.Lock()
- var ok2 = !current_ended
- _, ok := current_all_cruisers[addr]
- current_cruisers_mutex.Unlock()
- return ok && ok2
- }
- func end_cruises(cru []string) {
- current_cruisers_mutex.Lock()
- current_ended = true
- for _, str := range cru {
- conn := current_all_cruisers[str]
- if conn != nil {
- (*conn).Close()
- }
- delete(current_all_cruisers, str)
- }
- current_cruisers_mutex.Unlock()
- }
- func end_other_cruiser_conn(conn *net.Conn) {
- current_cruisers_mutex.Lock()
- for str, c := range current_all_cruisers {
- if conn != c && c != nil {
- (*c).Close()
- }
- delete(current_all_cruisers, str)
- }
- current_cruisers_mutex.Unlock()
- }
- func cruised_conn() (conn *net.Conn, addr string) {
- current_cruisers_mutex.Lock()
- for a, c := range current_all_cruisers {
- if c != nil {
- conn = c
- addr = a
- delete(current_all_cruisers, a)
- break
- }
- }
- current_cruisers_mutex.Unlock()
- return conn, addr
- }
- func cruised_address() (addr string) {
- current_cruisers_mutex.Lock()
- for a := range current_all_cruisers {
- addr = a
- break
- }
- if len(addr) == 0 {
- for a := range current_extra_cruisers {
- addr = a
- break
- }
- }
- current_cruisers_mutex.Unlock()
- return addr
- }
- func isIpV6(ip string) bool {
- for i := 0; i < len(ip); i++ {
- switch ip[i] {
- case '.':
- return false
- case ':':
- return true
- }
- }
- return true
- }
- func cruise(addr string) error {
- current_cruisers_mutex.Lock()
- if current_ended {
- current_cruisers_mutex.Unlock()
- return nil
- }
- if len(current_all_cruisers) >= max_cruisers {
- current_extra_cruisers[addr] = struct{}{}
- current_cruisers_mutex.Unlock()
- return fmt.Errorf("Max cruisers")
- }
- if _, ok := current_all_cruisers[addr]; ok {
- current_cruisers_mutex.Unlock()
- return nil
- }
- current_all_cruisers[addr] = nil
- current_cruisers_mutex.Unlock()
- pver := ProtocolVersion
- btcnet := MainNet
- conn, err := net.Dial("tcp", addr)
- if err != nil {
- return err
- }
- current_cruisers_mutex.Lock()
- current_all_cruisers[addr] = &conn
- current_cruisers_mutex.Unlock()
- nonce, err := RandomUint64()
- if err != nil {
- conn.Close()
- return err
- }
- msgVersion := NewMsgVersionFromConn(conn, nonce, 0, SFNodeNetwork|SFNodeWitness)
- if err := WriteMessage(conn, msgVersion, pver, btcnet); err != nil {
- conn.Close()
- return err
- }
- if err := msgVersion.AddUserAgent("Satoshi", "0.20.1"); err != nil {
- conn.Close()
- return err
- }
- msg, _, err := ReadMessage(conn, pver, btcnet)
- if err != nil {
- conn.Close()
- return err
- }
- vmsg, ok := msg.(*MsgVersion)
- if !ok {
- conn.Close()
- return fmt.Errorf("Cannot make msg version")
- }
- if uint32(vmsg.ProtocolVersion) < pver {
- pver = uint32(vmsg.ProtocolVersion)
- }
- if err := WriteMessage(conn, NewMsgVerAck(), pver, btcnet); err != nil {
- conn.Close()
- return err
- }
- getAddr := &MsgGetAddr{}
- if err := WriteMessage(conn, getAddr, pver, btcnet); err != nil {
- conn.Close()
- return err
- }
- for has_cruiser(addr) {
- msg, _, err := ReadMessage(conn, pver, btcnet)
- if err != nil {
- conn.Close()
- return err
- }
- if !has_cruiser(addr) {
- return nil
- }
- switch tmsg := msg.(type) {
- case *MsgAddr:
- for _, address := range tmsg.AddrList {
- fmt.Printf("Node address received: %s %d\n", address.IP, address.Port)
- if isIpV6(address.IP.String()) {
- go cruise(fmt.Sprintf("[%s]:%d", address.IP.String(), address.Port))
- } else {
- go cruise(fmt.Sprintf("%s:%d", address.IP.String(), address.Port))
- }
- }
- getAddr := &MsgGetAddr{}
- if err := WriteMessage(conn, getAddr, pver, btcnet); err != nil {
- conn.Close()
- return err
- }
- }
- }
- return nil
- }
- const downloader_start_height = 481824
- var data_downloader_mutex sync.Mutex
- var data_downloader_active bool
- var data_download_height uint64
- func data_downloader(conn *net.Conn, pver uint32, btcnet BitcoinNet) {
- data_downloader_mutex.Lock()
- if data_downloader_active {
- data_downloader_mutex.Unlock()
- return
- }
- data_downloader_active = true
- data_download_height = downloader_start_height
- data_downloader_mutex.Unlock()
- firstBlock := myGet(downloader_start_height)
- newData := NewMsgGetData()
- newData.AddInvVect(NewInvVect(InvTypeBlock, firstBlock))
- if err := WriteMessage(*conn, newData, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- }
- func downloader_height(hash *Hash) int64 {
- data_downloader_mutex.Lock()
- var near = data_download_height - 1
- data_downloader_mutex.Unlock()
- for i := near; i < near+3; i++ {
- block := myGet(i)
- if *block == *hash {
- return int64(i) + 1
- }
- }
- return -1
- }
- func continue_downloader(conn *net.Conn, pver uint32, btcnet BitcoinNet) bool {
- data_downloader_mutex.Lock()
- data_download_height++
- var height = data_download_height
- data_downloader_mutex.Unlock()
- firstBlock := myGet(height)
- if firstBlock == nil {
- return false
- }
- newData := NewMsgGetData()
- newData.AddInvVect(NewInvVect(InvTypeBlock, firstBlock))
- if err := WriteMessage(*conn, newData, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- return true
- }
- type MessageError struct {
- Func string
- Description string
- }
- func (e *MessageError) Error() string {
- if e.Func != "" {
- return fmt.Sprintf("%v: %v", e.Func, e.Description)
- }
- return e.Description
- }
- func messageError(f string, desc string) *MessageError {
- return &MessageError{Func: f, Description: desc}
- }
- func HashB(b []byte) []byte {
- hash := sha256.Sum256(b)
- return hash[:]
- }
- func HashH(b []byte) Hash {
- return Hash(sha256.Sum256(b))
- }
- func DoubleHashB(b []byte) []byte {
- first := sha256.Sum256(b)
- second := sha256.Sum256(first[:])
- return second[:]
- }
- func DoubleHashH(b []byte) Hash {
- first := sha256.Sum256(b)
- return Hash(sha256.Sum256(first[:]))
- }
- const HashSize = 32
- const MaxHashStringSize = HashSize * 2
- var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
- type Hash [HashSize]byte
- func (hash Hash) String() string {
- for i := 0; i < HashSize/2; i++ {
- hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
- }
- return hex.EncodeToString(hash[:])
- }
- func (hash *Hash) CloneBytes() []byte {
- newHash := make([]byte, HashSize)
- copy(newHash, hash[:])
- return newHash
- }
- func (hash *Hash) SetBytes(newHash []byte) error {
- nhlen := len(newHash)
- if nhlen != HashSize {
- return fmt.Errorf("invalid hash length of %v, want %v", nhlen,
- HashSize)
- }
- copy(hash[:], newHash)
- return nil
- }
- func (hash *Hash) IsEqual(target *Hash) bool {
- if hash == nil && target == nil {
- return true
- }
- if hash == nil || target == nil {
- return false
- }
- return *hash == *target
- }
- func NewHash(newHash []byte) (*Hash, error) {
- var sh Hash
- err := sh.SetBytes(newHash)
- if err != nil {
- return nil, err
- }
- return &sh, err
- }
- func NewHashFromStr(hash string) (*Hash, error) {
- ret := new(Hash)
- err := Decode(ret, hash)
- if err != nil {
- return nil, err
- }
- return ret, nil
- }
- func Decode(dst *Hash, src string) error {
- if len(src) > MaxHashStringSize {
- return ErrHashStrSize
- }
- var srcBytes []byte
- if len(src)%2 == 0 {
- srcBytes = []byte(src)
- } else {
- srcBytes = make([]byte, 1+len(src))
- srcBytes[0] = '0'
- copy(srcBytes[1:], src)
- }
- var reversedHash Hash
- _, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(srcBytes)):], srcBytes)
- if err != nil {
- return err
- }
- for i, b := range reversedHash[:HashSize/2] {
- dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
- }
- return nil
- }
- const (
- MaxInvPerMsg = 50000
- maxInvVectPayload = 4 + HashSize
- InvWitnessFlag = 1 << 30
- )
- type InvType uint32
- const (
- InvTypeError InvType = 0
- InvTypeTx InvType = 1
- InvTypeBlock InvType = 2
- InvTypeFilteredBlock InvType = 3
- InvTypeWitnessBlock InvType = InvTypeBlock | InvWitnessFlag
- InvTypeWitnessTx InvType = InvTypeTx | InvWitnessFlag
- InvTypeFilteredWitnessBlock InvType = InvTypeFilteredBlock | InvWitnessFlag
- )
- var ivStrings = map[InvType]string{
- InvTypeError: "ERROR",
- InvTypeTx: "MSG_TX",
- InvTypeBlock: "MSG_BLOCK",
- InvTypeFilteredBlock: "MSG_FILTERED_BLOCK",
- InvTypeWitnessBlock: "MSG_WITNESS_BLOCK",
- InvTypeWitnessTx: "MSG_WITNESS_TX",
- InvTypeFilteredWitnessBlock: "MSG_FILTERED_WITNESS_BLOCK",
- }
- func (invtype InvType) String() string {
- if s, ok := ivStrings[invtype]; ok {
- return s
- }
- return fmt.Sprintf("Unknown InvType (%d)", uint32(invtype))
- }
- type InvVect struct {
- Type InvType
- Hash Hash
- }
- func NewInvVect(typ InvType, hash *Hash) *InvVect {
- return &InvVect{
- Type: typ,
- Hash: *hash,
- }
- }
- func readInvVect(r io.Reader, pver uint32, iv *InvVect) error {
- return readElements(r, &iv.Type, &iv.Hash)
- }
- func writeInvVect(w io.Writer, pver uint32, iv *InvVect) error {
- return writeElements(w, iv.Type, &iv.Hash)
- }
- func NewMsgVersionFromConn(conn net.Conn, nonce uint64,
- lastBlock int32, sf ServiceFlag) *MsgVersion {
- lna := NewNetAddress(conn.LocalAddr().(*net.TCPAddr), sf)
- rna := NewNetAddress(conn.RemoteAddr().(*net.TCPAddr), sf)
- return NewMsgVersion(lna, rna, nonce, lastBlock)
- }
- func main() {
- hashStr := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
- locatorHash, err := NewHashFromStr(hashStr)
- if err != nil {
- log.Printf("NewShaHashFromStr: %v", err)
- }
- myPut(locatorHash, 0)
- var cru = []string{
- "bitcoin.vable.ch:8333", "testrestful.net:8333", "8an.z.praha12.net:8333", "greentheatre.kiev.ua:8333",
- "seed.bitcoin.sipa.be:8333",
- "dnsseed.bluematt.me:8333",
- "dnsseed.bitcoin.dashjr.org:8333",
- "seed.bitcoinstats.com:8333",
- "seed.bitcoin.jonasschnelli.ch:8333",
- "seed.btc.petertodd.org:8333",
- }
- start_cruises(cru)
- for cruiser_pending_extra_address() {
- time.Sleep(1 * time.Second)
- }
- end_cruises(cru)
- pver := ProtocolVersion
- btcnet := MainNet
- var conn net.Conn
- connect, addr := cruised_conn()
- if connect == nil {
- var addr string
- for {
- var err error
- addr = cruised_address()
- log.Printf("Connecting to %s\n", addr)
- conn, err = net.DialTimeout("tcp", addr, 3*time.Second)
- if err != nil {
- log.Print(err)
- continue
- }
- }
- defer conn.Close()
- log.Printf("Connected to %s\n", addr)
- nonce, err := RandomUint64()
- if err != nil {
- log.Fatal(err)
- }
- msgVersion := NewMsgVersionFromConn(conn, nonce, 0, SFNodeNetwork|SFNodeWitness)
- if err := WriteMessage(conn, msgVersion, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- if err := msgVersion.AddUserAgent("Satoshi", "0.20.1"); err != nil {
- log.Fatal(err)
- }
- log.Printf("Version message sent to %s\n", addr)
- msg, _, err := ReadMessage(conn, pver, btcnet)
- if err != nil {
- log.Fatal(err)
- }
- vmsg, ok := msg.(*MsgVersion)
- if !ok {
- log.Fatalf("Did not receive version message: %T", vmsg)
- return
- }
- if uint32(vmsg.ProtocolVersion) < pver {
- pver = uint32(vmsg.ProtocolVersion)
- }
- log.Printf("Version response received from %s\n", addr)
- if err := WriteMessage(conn, NewMsgVerAck(), pver, btcnet); err != nil {
- log.Fatal(err)
- }
- } else {
- log.Printf("Ending other cruisers than %s\n", addr)
- end_other_cruiser_conn(connect)
- log.Printf("Retaining connection %s\n", addr)
- conn = *connect
- nonce, err := RandomUint64()
- if err != nil {
- log.Fatal("RandomUint64: Error generating nonce: %v", err)
- }
- pingMsg := NewMsgPing(nonce)
- if err := WriteMessage(conn, pingMsg, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- newHdrs := NewMsgGetHeaders()
- newHdrs.ProtocolVersion = pver
- newHdrs.AddBlockLocatorHash(locatorHash)
- if err := WriteMessage(conn, newHdrs, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- }
- SetupCloseHandler(&conn)
- var commits_db *os.File
- var commits_db_checksum [32]byte
- var headerSyncOver bool
- bar := Bar{Graph: "#", Unit: "headers"}
- var total_coins uint64
- var obviously_claimed_coins uint64
- for {
- msg, _, err := ReadMessage(conn, pver, btcnet)
- if err != nil {
- bar.Hide()
- log.Printf("Failed to read message: %v", err)
- bar.Finish()
- if headerSyncOver {
- commits_db.Write(commits_db_checksum[0:32])
- commits_db.Close()
- }
- break
- }
- switch tmsg := msg.(type) {
- case *MsgInv:
- var is_new_block = false
- for _, inv := range tmsg.InvList {
- if inv.Type == InvTypeBlock {
- if !myHas(&inv.Hash) {
- is_new_block = true
- }
- }
- }
- if is_new_block && headerSyncOver {
- newHdrs := NewMsgGetHeaders()
- newHdrs.ProtocolVersion = pver
- myLocator(10, 6, func(id uint64, hash *Hash) {
- newHdrs.AddBlockLocatorHash(hash)
- })
- if err := WriteMessage(conn, newHdrs, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- }
- continue
- case *MsgPing:
- bar.Hide()
- log.Printf("ping received from %s\n", addr)
- bar.Replay()
- if err := WriteMessage(conn, NewMsgPong(tmsg.Nonce), pver, btcnet); err != nil {
- log.Fatal(err)
- }
- case *MsgHeaders:
- var oldStatus = myStatus(func(tot uint64, hsh *Hash) {
- bar.Hide()
- log.Printf("top header %d %s\n", tot, *hsh)
- bar.Replay()
- })
- for _, hdr := range tmsg.Headers {
- myAttach(hdr, func(ra, rb *Hash) {
- bar.Hide()
- log.Println("Reorg %s %s\n", *ra, *rb)
- bar.Replay()
- })
- }
- if oldStatus != myStatus(func(tot uint64, hsh *Hash) {
- bar.Hide()
- log.Printf("tip header %d %s\n", tot, *hsh)
- if headerSyncOver {
- bar.Replay()
- } else {
- bar.Play(0, int64(tot), myTotalBlocksEstimate())
- }
- }) {
- newHdrs := NewMsgGetHeaders()
- newHdrs.ProtocolVersion = pver
- myLocator(10, 0, func(id uint64, hash *Hash) {
- newHdrs.AddBlockLocatorHash(hash)
- })
- if err := WriteMessage(conn, newHdrs, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- } else {
- if !headerSyncOver {
- headerSyncOver = true
- data_downloader(&conn, pver, btcnet)
- bar.Restart("blocks")
- var err8 error
- commits_db, err = os.Create("commits.db")
- if err8 != nil {
- log.Fatal(err8)
- }
- }
- }
- case *MsgVerAck:
- bar.Hide()
- log.Printf("Version ack received from %s\n", addr)
- bar.Replay()
- newHdrs := NewMsgGetHeaders()
- newHdrs.ProtocolVersion = pver
- newHdrs.AddBlockLocatorHash(locatorHash)
- if err := WriteMessage(conn, newHdrs, pver, btcnet); err != nil {
- log.Fatal(err)
- }
- continue
- case *MsgAddr:
- for _, address := range tmsg.AddrList {
- bar.Hide()
- log.Printf("Node address received: %s %d\n", address.IP, address.Port)
- bar.Replay()
- }
- case *MsgBlock:
- var height = downloader_height(&tmsg.Header.PrevBlock)
- var combbase = true
- if height >= 0 {
- var blkHash = tmsg.Header.BlockHash()
- if !myHas(&blkHash) {
- bar.Hide()
- log.Fatalf("Received block %s on height %d not in chain\n", blkHash, height)
- }
- var merkle []Hash
- var q = 0
- for i, tx := range tmsg.Transactions {
- var hash = tx.TxHash()
- merkle = append(merkle, hash)
- for j, txout := range tx.TxOut {
- if len(txout.PkScript) == 34 {
- if txout.PkScript[0] == 0 && txout.PkScript[1] == 0x20 {
- var buf [32]byte
- var buf2 [8]byte
- copy(buf[0:32], txout.PkScript[2:])
- if is_previously_unseen_make_seen(&buf) {
- if combbase {
- combbase = false
- var log = math.Log2(float64(height))
- log = log * log * log * log * log * log
- var combbase_value = 210000000 - uint64(log)
- total_coins += combbase_value
- if height >= 601002 && (txout.Value == 546 || txout.Value == 330) {
- obviously_claimed_coins += combbase_value
- }
- }
- if height >= 620000 {
- BCDFromUint(uint64(height), buf2[0:4])
- BCDFromUint(uint64(q), buf2[4:8])
- bar.Hide()
- log.Printf("%X %08d %08d %d", buf, height, q, txout.Value)
- bar.Replay()
- } else {
- BCDFromUint(uint64(height), buf2[0:4])
- BCDFromUint(uint64(i), buf2[4:6])
- BCDFromUint(uint64(j), buf2[6:8])
- bar.Hide()
- log.Printf("%X %08d %04d %04d %d", buf, height, i, j, txout.Value)
- bar.Replay()
- }
- commits_db.Write(buf[0:32])
- commits_db.Write(buf2[0:8])
- aes_checksum(&buf, &commits_db_checksum)
- }
- q++
- }
- }
- }
- }
- if merkleTree(merkle) != tmsg.Header.MerkleRoot {
- bar.Hide()
- log.Fatalf("Received block %d merkle root is not valid\n", height)
- }
- bar.Play(downloader_start_height, height, int64(myStatus(nil)))
- if headerSyncOver {
- if !continue_downloader(&conn, pver, btcnet) {
- commits_db.Write(commits_db_checksum[0:32])
- commits_db.Close()
- bar.Hide()
- log.Printf("Success! Total coins: %d.%08d, obviously claimed coins: %d.%08d\n",
- total_coins/100000000, total_coins%100000000,
- obviously_claimed_coins/100000000, obviously_claimed_coins%100000000)
- os.Exit(0)
- }
- }
- } else {
- bar.Hide()
- log.Fatalf("Received block %s not in headers chain", tmsg.Header.BlockHash())
- }
- default:
- continue
- }
- }
- }
- func merkleTree(merkle []Hash) Hash {
- if len(merkle) == 0 {
- return Hash{}
- }
- if len(merkle) == 1 {
- return merkle[0]
- }
- for len(merkle) > 1 {
- if len(merkle)%2 != 0 {
- merkle = append(merkle, merkle[len(merkle)-1])
- }
- var newMerkle []Hash
- for i := 0; i < len(merkle)/2; i++ {
- var buf [64]byte
- copy(buf[0:32], merkle[2*i][0:])
- copy(buf[32:64], merkle[2*i+1][0:])
- newMerkle = append(newMerkle, DoubleHashH(buf[0:64]))
- }
- merkle = newMerkle
- }
- return merkle[0]
- }
- const MessageHeaderSize = 24
- const CommandSize = 12
- const MaxMessagePayload = (1024 * 1024 * 32)
- const (
- CmdVersion = "version"
- CmdVerAck = "verack"
- CmdGetAddr = "getaddr"
- CmdAddr = "addr"
- CmdGetBlocks = "getblocks"
- CmdInv = "inv"
- CmdGetData = "getdata"
- CmdNotFound = "notfound"
- CmdBlock = "block"
- CmdTx = "tx"
- CmdGetHeaders = "getheaders"
- CmdHeaders = "headers"
- CmdPing = "ping"
- CmdPong = "pong"
- CmdAlert = "alert"
- CmdMemPool = "mempool"
- CmdFilterAdd = "filteradd"
- CmdFilterClear = "filterclear"
- CmdFilterLoad = "filterload"
- CmdMerkleBlock = "merkleblock"
- CmdReject = "reject"
- CmdSendHeaders = "sendheaders"
- CmdFeeFilter = "feefilter"
- CmdGetCFilters = "getcfilters"
- CmdGetCFHeaders = "getcfheaders"
- CmdGetCFCheckpt = "getcfcheckpt"
- CmdCFilter = "cfilter"
- CmdCFHeaders = "cfheaders"
- CmdCFCheckpt = "cfcheckpt"
- )
- type MessageEncoding uint32
- const (
- BaseEncoding MessageEncoding = 1 << iota
- WitnessEncoding
- )
- var LatestEncoding = WitnessEncoding
- type Message interface {
- BtcDecode(io.Reader, uint32, MessageEncoding) error
- BtcEncode(io.Writer, uint32, MessageEncoding) error
- Command() string
- MaxPayloadLength(uint32) uint32
- }
- func makeEmptyMessage(command string) (Message, error) {
- var msg Message
- switch command {
- case CmdVersion:
- msg = &MsgVersion{}
- case CmdVerAck:
- msg = &MsgVerAck{}
- case CmdGetAddr:
- msg = &MsgGetAddr{}
- case CmdAddr:
- msg = &MsgAddr{}
- case CmdGetBlocks:
- msg = &MsgGetBlocks{}
- case CmdBlock:
- msg = &MsgBlock{}
- case CmdInv:
- msg = &MsgInv{}
- case CmdGetData:
- msg = &MsgGetData{}
- case CmdNotFound:
- msg = &MsgNotFound{}
- case CmdTx:
- msg = &MsgTx{}
- case CmdPing:
- msg = &MsgPing{}
- case CmdPong:
- msg = &MsgPong{}
- case CmdGetHeaders:
- msg = &MsgGetHeaders{}
- case CmdHeaders:
- msg = &MsgHeaders{}
- case CmdAlert:
- msg = &MsgAlert{}
- case CmdMemPool:
- msg = &MsgMemPool{}
- case CmdFilterAdd:
- msg = &MsgFilterAdd{}
- case CmdFilterClear:
- msg = &MsgFilterClear{}
- case CmdFilterLoad:
- msg = &MsgFilterLoad{}
- case CmdMerkleBlock:
- msg = &MsgMerkleBlock{}
- case CmdReject:
- msg = &MsgReject{}
- case CmdSendHeaders:
- msg = &MsgSendHeaders{}
- case CmdFeeFilter:
- msg = &MsgFeeFilter{}
- case CmdGetCFilters:
- msg = &MsgGetCFilters{}
- case CmdGetCFHeaders:
- msg = &MsgGetCFHeaders{}
- case CmdGetCFCheckpt:
- msg = &MsgGetCFCheckpt{}
- case CmdCFilter:
- msg = &MsgCFilter{}
- case CmdCFHeaders:
- msg = &MsgCFHeaders{}
- case CmdCFCheckpt:
- msg = &MsgCFCheckpt{}
- default:
- return nil, fmt.Errorf("unhandled command [%s]", command)
- }
- return msg, nil
- }
- type messageHeader struct {
- magic BitcoinNet
- command string
- length uint32
- checksum [4]byte
- }
- func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
- var headerBytes [MessageHeaderSize]byte
- n, err := io.ReadFull(r, headerBytes[:])
- if err != nil {
- return n, nil, err
- }
- hr := bytes.NewReader(headerBytes[:])
- hdr := messageHeader{}
- var command [CommandSize]byte
- readElements(hr, &hdr.magic, &command, &hdr.length, &hdr.checksum)
- hdr.command = string(bytes.TrimRight(command[:], "\x00"))
- return n, &hdr, nil
- }
- func discardInput(r io.Reader, n uint32) {
- maxSize := uint32(10 * 1024)
- numReads := n / maxSize
- bytesRemaining := n % maxSize
- if n > 0 {
- buf := make([]byte, maxSize)
- for i := uint32(0); i < numReads; i++ {
- io.ReadFull(r, buf)
- }
- }
- if bytesRemaining > 0 {
- buf := make([]byte, bytesRemaining)
- io.ReadFull(r, buf)
- }
- }
- func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (int, error) {
- return WriteMessageWithEncodingN(w, msg, pver, btcnet, BaseEncoding)
- }
- func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error {
- _, err := WriteMessageN(w, msg, pver, btcnet)
- return err
- }
- func WriteMessageWithEncodingN(w io.Writer, msg Message, pver uint32,
- btcnet BitcoinNet, encoding MessageEncoding) (int, error) {
- totalBytes := 0
- var command [CommandSize]byte
- cmd := msg.Command()
- if len(cmd) > CommandSize {
- str := fmt.Sprintf("command [%s] is too long [max %v]",
- cmd, CommandSize)
- return totalBytes, messageError("WriteMessage", str)
- }
- copy(command[:], []byte(cmd))
- var bw bytes.Buffer
- err := msg.BtcEncode(&bw, pver, encoding)
- if err != nil {
- return totalBytes, err
- }
- payload := bw.Bytes()
- lenp := len(payload)
- if lenp > MaxMessagePayload {
- str := fmt.Sprintf("message payload is too large - encoded "+
- "%d bytes, but maximum message payload is %d bytes",
- lenp, MaxMessagePayload)
- return totalBytes, messageError("WriteMessage", str)
- }
- mpl := msg.MaxPayloadLength(pver)
- if uint32(lenp) > mpl {
- str := fmt.Sprintf("message payload is too large - encoded "+
- "%d bytes, but maximum message payload size for "+
- "messages of type [%s] is %d.", lenp, cmd, mpl)
- return totalBytes, messageError("WriteMessage", str)
- }
- hdr := messageHeader{}
- hdr.magic = btcnet
- hdr.command = cmd
- hdr.length = uint32(lenp)
- copy(hdr.checksum[:], DoubleHashB(payload)[0:4])
- hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
- writeElements(hw, hdr.magic, command, hdr.length, hdr.checksum)
- n, err := w.Write(hw.Bytes())
- totalBytes += n
- if err != nil {
- return totalBytes, err
- }
- if len(payload) > 0 {
- n, err = w.Write(payload)
- totalBytes += n
- }
- return totalBytes, err
- }
- func ReadMessageWithEncodingN(r io.Reader, pver uint32, btcnet BitcoinNet,
- enc MessageEncoding) (int, Message, []byte, error) {
- totalBytes := 0
- n, hdr, err := readMessageHeader(r)
- totalBytes += n
- if err != nil {
- return totalBytes, nil, nil, err
- }
- if hdr.length > MaxMessagePayload {
- str := fmt.Sprintf("message payload is too large - header "+
- "indicates %d bytes, but max message payload is %d "+
- "bytes.", hdr.length, MaxMessagePayload)
- return totalBytes, nil, nil, messageError("ReadMessage", str)
- }
- if hdr.magic != btcnet {
- discardInput(r, hdr.length)
- str := fmt.Sprintf("message from other network [%v]", hdr.magic)
- return totalBytes, nil, nil, messageError("ReadMessage", str)
- }
- command := hdr.command
- if !utf8.ValidString(command) {
- discardInput(r, hdr.length)
- str := fmt.Sprintf("invalid command %v", []byte(command))
- return totalBytes, nil, nil, messageError("ReadMessage", str)
- }
- msg, err := makeEmptyMessage(command)
- if err != nil {
- discardInput(r, hdr.length)
- return totalBytes, nil, nil, messageError("ReadMessage",
- err.Error())
- }
- mpl := msg.MaxPayloadLength(pver)
- if hdr.length > mpl {
- discardInput(r, hdr.length)
- str := fmt.Sprintf("payload exceeds max length - header "+
- "indicates %v bytes, but max payload size for "+
- "messages of type [%v] is %v.", hdr.length, command, mpl)
- return totalBytes, nil, nil, messageError("ReadMessage", str)
- }
- payload := make([]byte, hdr.length)
- n, err = io.ReadFull(r, payload)
- totalBytes += n
- if err != nil {
- return totalBytes, nil, nil, err
- }
- checksum := DoubleHashB(payload)[0:4]
- if !bytes.Equal(checksum[:], hdr.checksum[:]) {
- str := fmt.Sprintf("payload checksum failed - header "+
- "indicates %v, but actual checksum is %v.",
- hdr.checksum, checksum)
- return totalBytes, nil, nil, messageError("ReadMessage", str)
- }
- pr := bytes.NewBuffer(payload)
- err = msg.BtcDecode(pr, pver, enc)
- if err != nil {
- return totalBytes, nil, nil, err
- }
- return totalBytes, msg, payload, nil
- }
- func ReadMessageN(r io.Reader, pver uint32, btcnet BitcoinNet) (int, Message, []byte, error) {
- return ReadMessageWithEncodingN(r, pver, btcnet, BaseEncoding)
- }
- func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) {
- _, msg, buf, err := ReadMessageN(r, pver, btcnet)
- return msg, buf, err
- }
- const MaxAddrPerMsg = 1000
- type MsgAddr struct {
- AddrList []*NetAddress
- }
- func (msg *MsgAddr) AddAddress(na *NetAddress) error {
- if len(msg.AddrList)+1 > MaxAddrPerMsg {
- str := fmt.Sprintf("too many addresses in message [max %v]",
- MaxAddrPerMsg)
- return messageError("MsgAddr.AddAddress", str)
- }
- msg.AddrList = append(msg.AddrList, na)
- return nil
- }
- func (msg *MsgAddr) AddAddresses(netAddrs ...*NetAddress) error {
- for _, na := range netAddrs {
- err := msg.AddAddress(na)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgAddr) ClearAddresses() {
- msg.AddrList = []*NetAddress{}
- }
- func (msg *MsgAddr) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxAddrPerMsg {
- str := fmt.Sprintf("too many addresses for message "+
- "[count %v, max %v]", count, MaxAddrPerMsg)
- return messageError("MsgAddr.BtcDecode", str)
- }
- addrList := make([]NetAddress, count)
- msg.AddrList = make([]*NetAddress, 0, count)
- for i := uint64(0); i < count; i++ {
- na := &addrList[i]
- err := readNetAddress(r, pver, na, true)
- if err != nil {
- return err
- }
- msg.AddAddress(na)
- }
- return nil
- }
- func (msg *MsgAddr) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.AddrList)
- if pver < MultipleAddressVersion && count > 1 {
- str := fmt.Sprintf("too many addresses for message of "+
- "protocol version %v [count %v, max 1]", pver, count)
- return messageError("MsgAddr.BtcEncode", str)
- }
- if count > MaxAddrPerMsg {
- str := fmt.Sprintf("too many addresses for message "+
- "[count %v, max %v]", count, MaxAddrPerMsg)
- return messageError("MsgAddr.BtcEncode", str)
- }
- err := WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, na := range msg.AddrList {
- err = writeNetAddress(w, pver, na, true)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgAddr) Command() string {
- return CmdAddr
- }
- func (msg *MsgAddr) MaxPayloadLength(pver uint32) uint32 {
- if pver < MultipleAddressVersion {
- return MaxVarIntPayload + maxNetAddressPayload(pver)
- }
- return MaxVarIntPayload + (MaxAddrPerMsg * maxNetAddressPayload(pver))
- }
- func NewMsgAddr() *MsgAddr {
- return &MsgAddr{
- AddrList: make([]*NetAddress, 0, MaxAddrPerMsg),
- }
- }
- const fixedAlertSize = 45
- const maxSignatureSize = 72
- const maxAlertSize = MaxMessagePayload - maxSignatureSize - MaxVarIntPayload - 1
- const maxCountSetCancel = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4
- const maxCountSetSubVer = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 256
- type Alert struct {
- Version int32
- RelayUntil int64
- Expiration int64
- ID int32
- Cancel int32
- SetCancel []int32
- MinVer int32
- MaxVer int32
- SetSubVer []string
- Priority int32
- Comment string
- StatusBar string
- Reserved string
- }
- func (alert *Alert) Serialize(w io.Writer, pver uint32) error {
- err := writeElements(w, alert.Version, alert.RelayUntil,
- alert.Expiration, alert.ID, alert.Cancel)
- if err != nil {
- return err
- }
- count := len(alert.SetCancel)
- if count > maxCountSetCancel {
- str := fmt.Sprintf("too many cancel alert IDs for alert "+
- "[count %v, max %v]", count, maxCountSetCancel)
- return messageError("Alert.Serialize", str)
- }
- err = WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for i := 0; i < count; i++ {
- err = writeElement(w, alert.SetCancel[i])
- if err != nil {
- return err
- }
- }
- err = writeElements(w, alert.MinVer, alert.MaxVer)
- if err != nil {
- return err
- }
- count = len(alert.SetSubVer)
- if count > maxCountSetSubVer {
- str := fmt.Sprintf("too many sub versions for alert "+
- "[count %v, max %v]", count, maxCountSetSubVer)
- return messageError("Alert.Serialize", str)
- }
- err = WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for i := 0; i < count; i++ {
- err = WriteVarString(w, pver, alert.SetSubVer[i])
- if err != nil {
- return err
- }
- }
- err = writeElement(w, alert.Priority)
- if err != nil {
- return err
- }
- err = WriteVarString(w, pver, alert.Comment)
- if err != nil {
- return err
- }
- err = WriteVarString(w, pver, alert.StatusBar)
- if err != nil {
- return err
- }
- return WriteVarString(w, pver, alert.Reserved)
- }
- func (alert *Alert) Deserialize(r io.Reader, pver uint32) error {
- err := readElements(r, &alert.Version, &alert.RelayUntil,
- &alert.Expiration, &alert.ID, &alert.Cancel)
- if err != nil {
- return err
- }
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > maxCountSetCancel {
- str := fmt.Sprintf("too many cancel alert IDs for alert "+
- "[count %v, max %v]", count, maxCountSetCancel)
- return messageError("Alert.Deserialize", str)
- }
- alert.SetCancel = make([]int32, count)
- for i := 0; i < int(count); i++ {
- err := readElement(r, &alert.SetCancel[i])
- if err != nil {
- return err
- }
- }
- err = readElements(r, &alert.MinVer, &alert.MaxVer)
- if err != nil {
- return err
- }
- count, err = ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > maxCountSetSubVer {
- str := fmt.Sprintf("too many sub versions for alert "+
- "[count %v, max %v]", count, maxCountSetSubVer)
- return messageError("Alert.Deserialize", str)
- }
- alert.SetSubVer = make([]string, count)
- for i := 0; i < int(count); i++ {
- alert.SetSubVer[i], err = ReadVarString(r, pver)
- if err != nil {
- return err
- }
- }
- err = readElement(r, &alert.Priority)
- if err != nil {
- return err
- }
- alert.Comment, err = ReadVarString(r, pver)
- if err != nil {
- return err
- }
- alert.StatusBar, err = ReadVarString(r, pver)
- if err != nil {
- return err
- }
- alert.Reserved, err = ReadVarString(r, pver)
- return err
- }
- func NewAlert(version int32, relayUntil int64, expiration int64,
- id int32, cancel int32, setCancel []int32, minVer int32,
- maxVer int32, setSubVer []string, priority int32, comment string,
- statusBar string) *Alert {
- return &Alert{
- Version: version,
- RelayUntil: relayUntil,
- Expiration: expiration,
- ID: id,
- Cancel: cancel,
- SetCancel: setCancel,
- MinVer: minVer,
- MaxVer: maxVer,
- SetSubVer: setSubVer,
- Priority: priority,
- Comment: comment,
- StatusBar: statusBar,
- Reserved: "",
- }
- }
- func NewAlertFromPayload(serializedPayload []byte, pver uint32) (*Alert, error) {
- var alert Alert
- r := bytes.NewReader(serializedPayload)
- err := alert.Deserialize(r, pver)
- if err != nil {
- return nil, err
- }
- return &alert, nil
- }
- type MsgAlert struct {
- SerializedPayload []byte
- Signature []byte
- Payload *Alert
- }
- func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- var err error
- msg.SerializedPayload, err = ReadVarBytes(r, pver, MaxMessagePayload,
- "alert serialized payload")
- if err != nil {
- return err
- }
- msg.Payload, err = NewAlertFromPayload(msg.SerializedPayload, pver)
- if err != nil {
- msg.Payload = nil
- }
- msg.Signature, err = ReadVarBytes(r, pver, MaxMessagePayload,
- "alert signature")
- return err
- }
- func (msg *MsgAlert) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- var err error
- var serializedpayload []byte
- if msg.Payload != nil {
- r := new(bytes.Buffer)
- err = msg.Payload.Serialize(r, pver)
- if err != nil {
- serializedpayload = msg.SerializedPayload
- } else {
- serializedpayload = r.Bytes()
- }
- } else {
- serializedpayload = msg.SerializedPayload
- }
- slen := uint64(len(serializedpayload))
- if slen == 0 {
- return messageError("MsgAlert.BtcEncode", "empty serialized payload")
- }
- err = WriteVarBytes(w, pver, serializedpayload)
- if err != nil {
- return err
- }
- return WriteVarBytes(w, pver, msg.Signature)
- }
- func (msg *MsgAlert) Command() string {
- return CmdAlert
- }
- func (msg *MsgAlert) MaxPayloadLength(pver uint32) uint32 {
- return MaxMessagePayload
- }
- func NewMsgAlert(serializedPayload []byte, signature []byte) *MsgAlert {
- return &MsgAlert{
- SerializedPayload: serializedPayload,
- Signature: signature,
- Payload: nil,
- }
- }
- const defaultTransactionAlloc = 2048
- const MaxBlocksPerMsg = 500
- const MaxBlockPayload = 4000000
- const maxTxPerBlock = (MaxBlockPayload / minTxPayload) + 1
- type TxLoc struct {
- TxStart int
- TxLen int
- }
- type MsgBlock struct {
- Header BlockHeader
- Transactions []*MsgTx
- }
- func (msg *MsgBlock) AddTransaction(tx *MsgTx) error {
- msg.Transactions = append(msg.Transactions, tx)
- return nil
- }
- func (msg *MsgBlock) ClearTransactions() {
- msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc)
- }
- func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- err := readBlockHeader(r, pver, &msg.Header)
- if err != nil {
- return err
- }
- txCount, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if txCount > maxTxPerBlock {
- str := fmt.Sprintf("too many transactions to fit into a block "+
- "[count %d, max %d]", txCount, maxTxPerBlock)
- return messageError("MsgBlock.BtcDecode", str)
- }
- msg.Transactions = make([]*MsgTx, 0, txCount)
- for i := uint64(0); i < txCount; i++ {
- tx := MsgTx{}
- err := tx.BtcDecode(r, pver, enc)
- if err != nil {
- return err
- }
- msg.Transactions = append(msg.Transactions, &tx)
- }
- return nil
- }
- func (msg *MsgBlock) Deserialize(r io.Reader) error {
- return msg.BtcDecode(r, 0, WitnessEncoding)
- }
- func (msg *MsgBlock) DeserializeNoWitness(r io.Reader) error {
- return msg.BtcDecode(r, 0, BaseEncoding)
- }
- func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
- fullLen := r.Len()
- err := readBlockHeader(r, 0, &msg.Header)
- if err != nil {
- return nil, err
- }
- txCount, err := ReadVarInt(r, 0)
- if err != nil {
- return nil, err
- }
- if txCount > maxTxPerBlock {
- str := fmt.Sprintf("too many transactions to fit into a block "+
- "[count %d, max %d]", txCount, maxTxPerBlock)
- return nil, messageError("MsgBlock.DeserializeTxLoc", str)
- }
- msg.Transactions = make([]*MsgTx, 0, txCount)
- txLocs := make([]TxLoc, txCount)
- for i := uint64(0); i < txCount; i++ {
- txLocs[i].TxStart = fullLen - r.Len()
- tx := MsgTx{}
- err := tx.Deserialize(r)
- if err != nil {
- return nil, err
- }
- msg.Transactions = append(msg.Transactions, &tx)
- txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart
- }
- return txLocs, nil
- }
- func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- err := writeBlockHeader(w, pver, &msg.Header)
- if err != nil {
- return err
- }
- err = WriteVarInt(w, pver, uint64(len(msg.Transactions)))
- if err != nil {
- return err
- }
- for _, tx := range msg.Transactions {
- err = tx.BtcEncode(w, pver, enc)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgBlock) Serialize(w io.Writer) error {
- return msg.BtcEncode(w, 0, WitnessEncoding)
- }
- func (msg *MsgBlock) SerializeNoWitness(w io.Writer) error {
- return msg.BtcEncode(w, 0, BaseEncoding)
- }
- func (msg *MsgBlock) SerializeSize() int {
- n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
- for _, tx := range msg.Transactions {
- n += tx.SerializeSize()
- }
- return n
- }
- func (msg *MsgBlock) SerializeSizeStripped() int {
- n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
- for _, tx := range msg.Transactions {
- n += tx.SerializeSizeStripped()
- }
- return n
- }
- func (msg *MsgBlock) Command() string {
- return CmdBlock
- }
- func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 {
- return MaxBlockPayload
- }
- func (msg *MsgBlock) BlockHash() Hash {
- return msg.Header.BlockHash()
- }
- func (msg *MsgBlock) TxHashes() ([]Hash, error) {
- hashList := make([]Hash, 0, len(msg.Transactions))
- for _, tx := range msg.Transactions {
- hashList = append(hashList, tx.TxHash())
- }
- return hashList, nil
- }
- func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
- return &MsgBlock{
- Header: *blockHeader,
- Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
- }
- }
- const (
- CFCheckptInterval = 1000
- maxCFHeadersLen = 100000
- )
- var ErrInsaneCFHeaderCount = errors.New(
- "refusing to decode unreasonable number of filter headers")
- type MsgCFCheckpt struct {
- FilterType FilterType
- StopHash Hash
- FilterHeaders []*Hash
- }
- func (msg *MsgCFCheckpt) AddCFHeader(header *Hash) error {
- if len(msg.FilterHeaders) == cap(msg.FilterHeaders) {
- str := fmt.Sprintf("FilterHeaders has insufficient capacity for "+
- "additional header: len = %d", len(msg.FilterHeaders))
- return messageError("MsgCFCheckpt.AddCFHeader", str)
- }
- msg.FilterHeaders = append(msg.FilterHeaders, header)
- return nil
- }
- func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
- err := readElement(r, &msg.FilterType)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.StopHash)
- if err != nil {
- return err
- }
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > maxCFHeadersLen {
- return ErrInsaneCFHeaderCount
- }
- msg.FilterHeaders = make([]*Hash, count)
- for i := uint64(0); i < count; i++ {
- var cfh Hash
- err := readElement(r, &cfh)
- if err != nil {
- return err
- }
- msg.FilterHeaders[i] = &cfh
- }
- return nil
- }
- func (msg *MsgCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
- err := writeElement(w, msg.FilterType)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.StopHash)
- if err != nil {
- return err
- }
- count := len(msg.FilterHeaders)
- err = WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, cfh := range msg.FilterHeaders {
- err := writeElement(w, cfh)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgCFCheckpt) Deserialize(r io.Reader) error {
- return msg.BtcDecode(r, 0, BaseEncoding)
- }
- func (msg *MsgCFCheckpt) Command() string {
- return CmdCFCheckpt
- }
- func (msg *MsgCFCheckpt) MaxPayloadLength(pver uint32) uint32 {
- return MaxMessagePayload
- }
- func NewMsgCFCheckpt(filterType FilterType, stopHash *Hash,
- headersCount int) *MsgCFCheckpt {
- return &MsgCFCheckpt{
- FilterType: filterType,
- StopHash: *stopHash,
- FilterHeaders: make([]*Hash, 0, headersCount),
- }
- }
- const (
- MaxCFHeaderPayload = HashSize
- MaxCFHeadersPerMsg = 2000
- )
- type MsgCFHeaders struct {
- FilterType FilterType
- StopHash Hash
- PrevFilterHeader Hash
- FilterHashes []*Hash
- }
- func (msg *MsgCFHeaders) AddCFHash(hash *Hash) error {
- if len(msg.FilterHashes)+1 > MaxCFHeadersPerMsg {
- str := fmt.Sprintf("too many block headers in message [max %v]",
- MaxBlockHeadersPerMsg)
- return messageError("MsgCFHeaders.AddCFHash", str)
- }
- msg.FilterHashes = append(msg.FilterHashes, hash)
- return nil
- }
- func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
- err := readElement(r, &msg.FilterType)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.StopHash)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.PrevFilterHeader)
- if err != nil {
- return err
- }
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxCFHeadersPerMsg {
- str := fmt.Sprintf("too many committed filter headers for "+
- "message [count %v, max %v]", count,
- MaxBlockHeadersPerMsg)
- return messageError("MsgCFHeaders.BtcDecode", str)
- }
- msg.FilterHashes = make([]*Hash, 0, count)
- for i := uint64(0); i < count; i++ {
- var cfh Hash
- err := readElement(r, &cfh)
- if err != nil {
- return err
- }
- msg.AddCFHash(&cfh)
- }
- return nil
- }
- func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
- err := writeElement(w, msg.FilterType)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.StopHash)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.PrevFilterHeader)
- if err != nil {
- return err
- }
- count := len(msg.FilterHashes)
- if count > MaxCFHeadersPerMsg {
- str := fmt.Sprintf("too many committed filter headers for "+
- "message [count %v, max %v]", count,
- MaxBlockHeadersPerMsg)
- return messageError("MsgCFHeaders.BtcEncode", str)
- }
- err = WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, cfh := range msg.FilterHashes {
- err := writeElement(w, cfh)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgCFHeaders) Deserialize(r io.Reader) error {
- return msg.BtcDecode(r, 0, BaseEncoding)
- }
- func (msg *MsgCFHeaders) Command() string {
- return CmdCFHeaders
- }
- func (msg *MsgCFHeaders) MaxPayloadLength(pver uint32) uint32 {
- return 1 + HashSize + HashSize + MaxVarIntPayload +
- (MaxCFHeaderPayload * MaxCFHeadersPerMsg)
- }
- func NewMsgCFHeaders() *MsgCFHeaders {
- return &MsgCFHeaders{
- FilterHashes: make([]*Hash, 0, MaxCFHeadersPerMsg),
- }
- }
- type FilterType uint8
- const (
- GCSFilterRegular FilterType = iota
- )
- const (
- MaxCFilterDataSize = 256 * 1024
- )
- type MsgCFilter struct {
- FilterType FilterType
- BlockHash Hash
- Data []byte
- }
- func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
- err := readElement(r, &msg.FilterType)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.BlockHash)
- if err != nil {
- return err
- }
- msg.Data, err = ReadVarBytes(r, pver, MaxCFilterDataSize,
- "cfilter data")
- return err
- }
- func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
- size := len(msg.Data)
- if size > MaxCFilterDataSize {
- str := fmt.Sprintf("cfilter size too large for message "+
- "[size %v, max %v]", size, MaxCFilterDataSize)
- return messageError("MsgCFilter.BtcEncode", str)
- }
- err := writeElement(w, msg.FilterType)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.BlockHash)
- if err != nil {
- return err
- }
- return WriteVarBytes(w, pver, msg.Data)
- }
- func (msg *MsgCFilter) Deserialize(r io.Reader) error {
- return msg.BtcDecode(r, 0, BaseEncoding)
- }
- func (msg *MsgCFilter) Command() string {
- return CmdCFilter
- }
- func (msg *MsgCFilter) MaxPayloadLength(pver uint32) uint32 {
- return uint32(VarIntSerializeSize(MaxCFilterDataSize)) +
- MaxCFilterDataSize + HashSize + 1
- }
- func NewMsgCFilter(filterType FilterType, blockHash *Hash,
- data []byte) *MsgCFilter {
- return &MsgCFilter{
- FilterType: filterType,
- BlockHash: *blockHash,
- Data: data,
- }
- }
- type MsgFeeFilter struct {
- MinFee int64
- }
- func (msg *MsgFeeFilter) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < FeeFilterVersion {
- str := fmt.Sprintf("feefilter message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFeeFilter.BtcDecode", str)
- }
- return readElement(r, &msg.MinFee)
- }
- func (msg *MsgFeeFilter) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < FeeFilterVersion {
- str := fmt.Sprintf("feefilter message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFeeFilter.BtcEncode", str)
- }
- return writeElement(w, msg.MinFee)
- }
- func (msg *MsgFeeFilter) Command() string {
- return CmdFeeFilter
- }
- func (msg *MsgFeeFilter) MaxPayloadLength(pver uint32) uint32 {
- return 8
- }
- func NewMsgFeeFilter(minfee int64) *MsgFeeFilter {
- return &MsgFeeFilter{
- MinFee: minfee,
- }
- }
- const (
- MaxFilterAddDataSize = 520
- )
- type MsgFilterAdd struct {
- Data []byte
- }
- func (msg *MsgFilterAdd) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("filteradd message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFilterAdd.BtcDecode", str)
- }
- var err error
- msg.Data, err = ReadVarBytes(r, pver, MaxFilterAddDataSize,
- "filteradd data")
- return err
- }
- func (msg *MsgFilterAdd) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("filteradd message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFilterAdd.BtcEncode", str)
- }
- size := len(msg.Data)
- if size > MaxFilterAddDataSize {
- str := fmt.Sprintf("filteradd size too large for message "+
- "[size %v, max %v]", size, MaxFilterAddDataSize)
- return messageError("MsgFilterAdd.BtcEncode", str)
- }
- return WriteVarBytes(w, pver, msg.Data)
- }
- func (msg *MsgFilterAdd) Command() string {
- return CmdFilterAdd
- }
- func (msg *MsgFilterAdd) MaxPayloadLength(pver uint32) uint32 {
- return uint32(VarIntSerializeSize(MaxFilterAddDataSize)) +
- MaxFilterAddDataSize
- }
- func NewMsgFilterAdd(data []byte) *MsgFilterAdd {
- return &MsgFilterAdd{
- Data: data,
- }
- }
- type MsgFilterClear struct{}
- func (msg *MsgFilterClear) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("filterclear message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFilterClear.BtcDecode", str)
- }
- return nil
- }
- func (msg *MsgFilterClear) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("filterclear message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFilterClear.BtcEncode", str)
- }
- return nil
- }
- func (msg *MsgFilterClear) Command() string {
- return CmdFilterClear
- }
- func (msg *MsgFilterClear) MaxPayloadLength(pver uint32) uint32 {
- return 0
- }
- func NewMsgFilterClear() *MsgFilterClear {
- return &MsgFilterClear{}
- }
- type BloomUpdateType uint8
- const (
- BloomUpdateNone BloomUpdateType = 0
- BloomUpdateAll BloomUpdateType = 1
- BloomUpdateP2PubkeyOnly BloomUpdateType = 2
- )
- const (
- MaxFilterLoadHashFuncs = 50
- MaxFilterLoadFilterSize = 36000
- )
- type MsgFilterLoad struct {
- Filter []byte
- HashFuncs uint32
- Tweak uint32
- Flags BloomUpdateType
- }
- func (msg *MsgFilterLoad) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("filterload message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFilterLoad.BtcDecode", str)
- }
- var err error
- msg.Filter, err = ReadVarBytes(r, pver, MaxFilterLoadFilterSize,
- "filterload filter size")
- if err != nil {
- return err
- }
- err = readElements(r, &msg.HashFuncs, &msg.Tweak, &msg.Flags)
- if err != nil {
- return err
- }
- if msg.HashFuncs > MaxFilterLoadHashFuncs {
- str := fmt.Sprintf("too many filter hash functions for message "+
- "[count %v, max %v]", msg.HashFuncs, MaxFilterLoadHashFuncs)
- return messageError("MsgFilterLoad.BtcDecode", str)
- }
- return nil
- }
- func (msg *MsgFilterLoad) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("filterload message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgFilterLoad.BtcEncode", str)
- }
- size := len(msg.Filter)
- if size > MaxFilterLoadFilterSize {
- str := fmt.Sprintf("filterload filter size too large for message "+
- "[size %v, max %v]", size, MaxFilterLoadFilterSize)
- return messageError("MsgFilterLoad.BtcEncode", str)
- }
- if msg.HashFuncs > MaxFilterLoadHashFuncs {
- str := fmt.Sprintf("too many filter hash functions for message "+
- "[count %v, max %v]", msg.HashFuncs, MaxFilterLoadHashFuncs)
- return messageError("MsgFilterLoad.BtcEncode", str)
- }
- err := WriteVarBytes(w, pver, msg.Filter)
- if err != nil {
- return err
- }
- return writeElements(w, msg.HashFuncs, msg.Tweak, msg.Flags)
- }
- func (msg *MsgFilterLoad) Command() string {
- return CmdFilterLoad
- }
- func (msg *MsgFilterLoad) MaxPayloadLength(pver uint32) uint32 {
- return uint32(VarIntSerializeSize(MaxFilterLoadFilterSize)) +
- MaxFilterLoadFilterSize + 9
- }
- func NewMsgFilterLoad(filter []byte, hashFuncs uint32, tweak uint32, flags BloomUpdateType) *MsgFilterLoad {
- return &MsgFilterLoad{
- Filter: filter,
- HashFuncs: hashFuncs,
- Tweak: tweak,
- Flags: flags,
- }
- }
- type MsgGetAddr struct{}
- func (msg *MsgGetAddr) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- return nil
- }
- func (msg *MsgGetAddr) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- return nil
- }
- func (msg *MsgGetAddr) Command() string {
- return CmdGetAddr
- }
- func (msg *MsgGetAddr) MaxPayloadLength(pver uint32) uint32 {
- return 0
- }
- func NewMsgGetAddr() *MsgGetAddr {
- return &MsgGetAddr{}
- }
- const MaxBlockLocatorsPerMsg = 500
- type MsgGetBlocks struct {
- ProtocolVersion uint32
- BlockLocatorHashes []*Hash
- HashStop Hash
- }
- func (msg *MsgGetBlocks) AddBlockLocatorHash(hash *Hash) error {
- if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg {
- str := fmt.Sprintf("too many block locator hashes for message [max %v]",
- MaxBlockLocatorsPerMsg)
- return messageError("MsgGetBlocks.AddBlockLocatorHash", str)
- }
- msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash)
- return nil
- }
- func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- err := readElement(r, &msg.ProtocolVersion)
- if err != nil {
- return err
- }
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxBlockLocatorsPerMsg {
- str := fmt.Sprintf("too many block locator hashes for message "+
- "[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
- return messageError("MsgGetBlocks.BtcDecode", str)
- }
- locatorHashes := make([]Hash, count)
- msg.BlockLocatorHashes = make([]*Hash, 0, count)
- for i := uint64(0); i < count; i++ {
- hash := &locatorHashes[i]
- err := readElement(r, hash)
- if err != nil {
- return err
- }
- msg.AddBlockLocatorHash(hash)
- }
- return readElement(r, &msg.HashStop)
- }
- func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.BlockLocatorHashes)
- if count > MaxBlockLocatorsPerMsg {
- str := fmt.Sprintf("too many block locator hashes for message "+
- "[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
- return messageError("MsgGetBlocks.BtcEncode", str)
- }
- err := writeElement(w, msg.ProtocolVersion)
- if err != nil {
- return err
- }
- err = WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, hash := range msg.BlockLocatorHashes {
- err = writeElement(w, hash)
- if err != nil {
- return err
- }
- }
- return writeElement(w, &msg.HashStop)
- }
- func (msg *MsgGetBlocks) Command() string {
- return CmdGetBlocks
- }
- func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 {
- return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize
- }
- func NewMsgGetBlocks(hashStop *Hash) *MsgGetBlocks {
- return &MsgGetBlocks{
- ProtocolVersion: ProtocolVersion,
- BlockLocatorHashes: make([]*Hash, 0, MaxBlockLocatorsPerMsg),
- HashStop: *hashStop,
- }
- }
- type MsgGetCFCheckpt struct {
- FilterType FilterType
- StopHash Hash
- }
- func (msg *MsgGetCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
- err := readElement(r, &msg.FilterType)
- if err != nil {
- return err
- }
- return readElement(r, &msg.StopHash)
- }
- func (msg *MsgGetCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
- err := writeElement(w, msg.FilterType)
- if err != nil {
- return err
- }
- return writeElement(w, &msg.StopHash)
- }
- func (msg *MsgGetCFCheckpt) Command() string {
- return CmdGetCFCheckpt
- }
- func (msg *MsgGetCFCheckpt) MaxPayloadLength(pver uint32) uint32 {
- return 1 + HashSize
- }
- func NewMsgGetCFCheckpt(filterType FilterType, stopHash *Hash) *MsgGetCFCheckpt {
- return &MsgGetCFCheckpt{
- FilterType: filterType,
- StopHash: *stopHash,
- }
- }
- type MsgGetCFHeaders struct {
- FilterType FilterType
- StartHeight uint32
- StopHash Hash
- }
- func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
- err := readElement(r, &msg.FilterType)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.StartHeight)
- if err != nil {
- return err
- }
- return readElement(r, &msg.StopHash)
- }
- func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
- err := writeElement(w, msg.FilterType)
- if err != nil {
- return err
- }
- err = writeElement(w, &msg.StartHeight)
- if err != nil {
- return err
- }
- return writeElement(w, &msg.StopHash)
- }
- func (msg *MsgGetCFHeaders) Command() string {
- return CmdGetCFHeaders
- }
- func (msg *MsgGetCFHeaders) MaxPayloadLength(pver uint32) uint32 {
- return 1 + 4 + HashSize
- }
- func NewMsgGetCFHeaders(filterType FilterType, startHeight uint32,
- stopHash *Hash) *MsgGetCFHeaders {
- return &MsgGetCFHeaders{
- FilterType: filterType,
- StartHeight: startHeight,
- StopHash: *stopHash,
- }
- }
- const MaxGetCFiltersReqRange = 1000
- type MsgGetCFilters struct {
- FilterType FilterType
- StartHeight uint32
- StopHash Hash
- }
- func (msg *MsgGetCFilters) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
- err := readElement(r, &msg.FilterType)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.StartHeight)
- if err != nil {
- return err
- }
- return readElement(r, &msg.StopHash)
- }
- func (msg *MsgGetCFilters) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
- err := writeElement(w, msg.FilterType)
- if err != nil {
- return err
- }
- err = writeElement(w, &msg.StartHeight)
- if err != nil {
- return err
- }
- return writeElement(w, &msg.StopHash)
- }
- func (msg *MsgGetCFilters) Command() string {
- return CmdGetCFilters
- }
- func (msg *MsgGetCFilters) MaxPayloadLength(pver uint32) uint32 {
- return 1 + 4 + HashSize
- }
- func NewMsgGetCFilters(filterType FilterType, startHeight uint32,
- stopHash *Hash) *MsgGetCFilters {
- return &MsgGetCFilters{
- FilterType: filterType,
- StartHeight: startHeight,
- StopHash: *stopHash,
- }
- }
- type MsgGetData struct {
- InvList []*InvVect
- }
- func (msg *MsgGetData) AddInvVect(iv *InvVect) error {
- if len(msg.InvList)+1 > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [max %v]",
- MaxInvPerMsg)
- return messageError("MsgGetData.AddInvVect", str)
- }
- msg.InvList = append(msg.InvList, iv)
- return nil
- }
- func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [%v]", count)
- return messageError("MsgGetData.BtcDecode", str)
- }
- invList := make([]InvVect, count)
- msg.InvList = make([]*InvVect, 0, count)
- for i := uint64(0); i < count; i++ {
- iv := &invList[i]
- err := readInvVect(r, pver, iv)
- if err != nil {
- return err
- }
- msg.AddInvVect(iv)
- }
- return nil
- }
- func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.InvList)
- if count > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [%v]", count)
- return messageError("MsgGetData.BtcEncode", str)
- }
- err := WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, iv := range msg.InvList {
- err := writeInvVect(w, pver, iv)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgGetData) Command() string {
- return CmdGetData
- }
- func (msg *MsgGetData) MaxPayloadLength(pver uint32) uint32 {
- return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload)
- }
- func NewMsgGetData() *MsgGetData {
- return &MsgGetData{
- InvList: make([]*InvVect, 0, defaultInvListAlloc),
- }
- }
- func NewMsgGetDataSizeHint(sizeHint uint) *MsgGetData {
- if sizeHint > MaxInvPerMsg {
- sizeHint = MaxInvPerMsg
- }
- return &MsgGetData{
- InvList: make([]*InvVect, 0, sizeHint),
- }
- }
- type MsgGetHeaders struct {
- ProtocolVersion uint32
- BlockLocatorHashes []*Hash
- HashStop Hash
- }
- func (msg *MsgGetHeaders) AddBlockLocatorHash(hash *Hash) error {
- if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg {
- str := fmt.Sprintf("too many block locator hashes for message [max %v]",
- MaxBlockLocatorsPerMsg)
- return messageError("MsgGetHeaders.AddBlockLocatorHash", str)
- }
- msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash)
- return nil
- }
- func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- err := readElement(r, &msg.ProtocolVersion)
- if err != nil {
- return err
- }
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxBlockLocatorsPerMsg {
- str := fmt.Sprintf("too many block locator hashes for message "+
- "[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
- return messageError("MsgGetHeaders.BtcDecode", str)
- }
- locatorHashes := make([]Hash, count)
- msg.BlockLocatorHashes = make([]*Hash, 0, count)
- for i := uint64(0); i < count; i++ {
- hash := &locatorHashes[i]
- err := readElement(r, hash)
- if err != nil {
- return err
- }
- msg.AddBlockLocatorHash(hash)
- }
- return readElement(r, &msg.HashStop)
- }
- func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.BlockLocatorHashes)
- if count > MaxBlockLocatorsPerMsg {
- str := fmt.Sprintf("too many block locator hashes for message "+
- "[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
- return messageError("MsgGetHeaders.BtcEncode", str)
- }
- err := writeElement(w, msg.ProtocolVersion)
- if err != nil {
- return err
- }
- err = WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, hash := range msg.BlockLocatorHashes {
- err := writeElement(w, hash)
- if err != nil {
- return err
- }
- }
- return writeElement(w, &msg.HashStop)
- }
- func (msg *MsgGetHeaders) Command() string {
- return CmdGetHeaders
- }
- func (msg *MsgGetHeaders) MaxPayloadLength(pver uint32) uint32 {
- return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg *
- HashSize) + HashSize
- }
- func NewMsgGetHeaders() *MsgGetHeaders {
- return &MsgGetHeaders{
- BlockLocatorHashes: make([]*Hash, 0,
- MaxBlockLocatorsPerMsg),
- }
- }
- const MaxBlockHeadersPerMsg = 2000
- type MsgHeaders struct {
- Headers []*BlockHeader
- }
- func (msg *MsgHeaders) AddBlockHeader(bh *BlockHeader) error {
- if len(msg.Headers)+1 > MaxBlockHeadersPerMsg {
- str := fmt.Sprintf("too many block headers in message [max %v]",
- MaxBlockHeadersPerMsg)
- return messageError("MsgHeaders.AddBlockHeader", str)
- }
- msg.Headers = append(msg.Headers, bh)
- return nil
- }
- func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxBlockHeadersPerMsg {
- str := fmt.Sprintf("too many block headers for message "+
- "[count %v, max %v]", count, MaxBlockHeadersPerMsg)
- return messageError("MsgHeaders.BtcDecode", str)
- }
- headers := make([]BlockHeader, count)
- msg.Headers = make([]*BlockHeader, 0, count)
- for i := uint64(0); i < count; i++ {
- bh := &headers[i]
- err := readBlockHeader(r, pver, bh)
- if err != nil {
- return err
- }
- txCount, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if txCount > 0 {
- str := fmt.Sprintf("block headers may not contain "+
- "transactions [count %v]", txCount)
- return messageError("MsgHeaders.BtcDecode", str)
- }
- msg.AddBlockHeader(bh)
- }
- return nil
- }
- func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.Headers)
- if count > MaxBlockHeadersPerMsg {
- str := fmt.Sprintf("too many block headers for message "+
- "[count %v, max %v]", count, MaxBlockHeadersPerMsg)
- return messageError("MsgHeaders.BtcEncode", str)
- }
- err := WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, bh := range msg.Headers {
- err := writeBlockHeader(w, pver, bh)
- if err != nil {
- return err
- }
- err = WriteVarInt(w, pver, 0)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgHeaders) Command() string {
- return CmdHeaders
- }
- func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 {
- return MaxVarIntPayload + ((MaxBlockHeaderPayload + 1) *
- MaxBlockHeadersPerMsg)
- }
- func NewMsgHeaders() *MsgHeaders {
- return &MsgHeaders{
- Headers: make([]*BlockHeader, 0, MaxBlockHeadersPerMsg),
- }
- }
- const defaultInvListAlloc = 1000
- type MsgInv struct {
- InvList []*InvVect
- }
- func (msg *MsgInv) AddInvVect(iv *InvVect) error {
- if len(msg.InvList)+1 > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [max %v]",
- MaxInvPerMsg)
- return messageError("MsgInv.AddInvVect", str)
- }
- msg.InvList = append(msg.InvList, iv)
- return nil
- }
- func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [%v]", count)
- return messageError("MsgInv.BtcDecode", str)
- }
- invList := make([]InvVect, count)
- msg.InvList = make([]*InvVect, 0, count)
- for i := uint64(0); i < count; i++ {
- iv := &invList[i]
- err := readInvVect(r, pver, iv)
- if err != nil {
- return err
- }
- msg.AddInvVect(iv)
- }
- return nil
- }
- func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.InvList)
- if count > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [%v]", count)
- return messageError("MsgInv.BtcEncode", str)
- }
- err := WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, iv := range msg.InvList {
- err := writeInvVect(w, pver, iv)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgInv) Command() string {
- return CmdInv
- }
- func (msg *MsgInv) MaxPayloadLength(pver uint32) uint32 {
- return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload)
- }
- func NewMsgInv() *MsgInv {
- return &MsgInv{
- InvList: make([]*InvVect, 0, defaultInvListAlloc),
- }
- }
- func NewMsgInvSizeHint(sizeHint uint) *MsgInv {
- if sizeHint > MaxInvPerMsg {
- sizeHint = MaxInvPerMsg
- }
- return &MsgInv{
- InvList: make([]*InvVect, 0, sizeHint),
- }
- }
- type MsgMemPool struct{}
- func (msg *MsgMemPool) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < BIP0035Version {
- str := fmt.Sprintf("mempool message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgMemPool.BtcDecode", str)
- }
- return nil
- }
- func (msg *MsgMemPool) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < BIP0035Version {
- str := fmt.Sprintf("mempool message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgMemPool.BtcEncode", str)
- }
- return nil
- }
- func (msg *MsgMemPool) Command() string {
- return CmdMemPool
- }
- func (msg *MsgMemPool) MaxPayloadLength(pver uint32) uint32 {
- return 0
- }
- func NewMsgMemPool() *MsgMemPool {
- return &MsgMemPool{}
- }
- const maxFlagsPerMerkleBlock = maxTxPerBlock / 8
- type MsgMerkleBlock struct {
- Header BlockHeader
- Transactions uint32
- Hashes []*Hash
- Flags []byte
- }
- func (msg *MsgMerkleBlock) AddTxHash(hash *Hash) error {
- if len(msg.Hashes)+1 > maxTxPerBlock {
- str := fmt.Sprintf("too many tx hashes for message [max %v]",
- maxTxPerBlock)
- return messageError("MsgMerkleBlock.AddTxHash", str)
- }
- msg.Hashes = append(msg.Hashes, hash)
- return nil
- }
- func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("merkleblock message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgMerkleBlock.BtcDecode", str)
- }
- err := readBlockHeader(r, pver, &msg.Header)
- if err != nil {
- return err
- }
- err = readElement(r, &msg.Transactions)
- if err != nil {
- return err
- }
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > maxTxPerBlock {
- str := fmt.Sprintf("too many transaction hashes for message "+
- "[count %v, max %v]", count, maxTxPerBlock)
- return messageError("MsgMerkleBlock.BtcDecode", str)
- }
- hashes := make([]Hash, count)
- msg.Hashes = make([]*Hash, 0, count)
- for i := uint64(0); i < count; i++ {
- hash := &hashes[i]
- err := readElement(r, hash)
- if err != nil {
- return err
- }
- msg.AddTxHash(hash)
- }
- msg.Flags, err = ReadVarBytes(r, pver, maxFlagsPerMerkleBlock,
- "merkle block flags size")
- return err
- }
- func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < BIP0037Version {
- str := fmt.Sprintf("merkleblock message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgMerkleBlock.BtcEncode", str)
- }
- numHashes := len(msg.Hashes)
- if numHashes > maxTxPerBlock {
- str := fmt.Sprintf("too many transaction hashes for message "+
- "[count %v, max %v]", numHashes, maxTxPerBlock)
- return messageError("MsgMerkleBlock.BtcDecode", str)
- }
- numFlagBytes := len(msg.Flags)
- if numFlagBytes > maxFlagsPerMerkleBlock {
- str := fmt.Sprintf("too many flag bytes for message [count %v, "+
- "max %v]", numFlagBytes, maxFlagsPerMerkleBlock)
- return messageError("MsgMerkleBlock.BtcDecode", str)
- }
- err := writeBlockHeader(w, pver, &msg.Header)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.Transactions)
- if err != nil {
- return err
- }
- err = WriteVarInt(w, pver, uint64(numHashes))
- if err != nil {
- return err
- }
- for _, hash := range msg.Hashes {
- err = writeElement(w, hash)
- if err != nil {
- return err
- }
- }
- return WriteVarBytes(w, pver, msg.Flags)
- }
- func (msg *MsgMerkleBlock) Command() string {
- return CmdMerkleBlock
- }
- func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
- return MaxBlockPayload
- }
- func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock {
- return &MsgMerkleBlock{
- Header: *bh,
- Transactions: 0,
- Hashes: make([]*Hash, 0),
- Flags: make([]byte, 0),
- }
- }
- type MsgNotFound struct {
- InvList []*InvVect
- }
- func (msg *MsgNotFound) AddInvVect(iv *InvVect) error {
- if len(msg.InvList)+1 > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [max %v]",
- MaxInvPerMsg)
- return messageError("MsgNotFound.AddInvVect", str)
- }
- msg.InvList = append(msg.InvList, iv)
- return nil
- }
- func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- if count > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [%v]", count)
- return messageError("MsgNotFound.BtcDecode", str)
- }
- invList := make([]InvVect, count)
- msg.InvList = make([]*InvVect, 0, count)
- for i := uint64(0); i < count; i++ {
- iv := &invList[i]
- err := readInvVect(r, pver, iv)
- if err != nil {
- return err
- }
- msg.AddInvVect(iv)
- }
- return nil
- }
- func (msg *MsgNotFound) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- count := len(msg.InvList)
- if count > MaxInvPerMsg {
- str := fmt.Sprintf("too many invvect in message [%v]", count)
- return messageError("MsgNotFound.BtcEncode", str)
- }
- err := WriteVarInt(w, pver, uint64(count))
- if err != nil {
- return err
- }
- for _, iv := range msg.InvList {
- err := writeInvVect(w, pver, iv)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgNotFound) Command() string {
- return CmdNotFound
- }
- func (msg *MsgNotFound) MaxPayloadLength(pver uint32) uint32 {
- return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload)
- }
- func NewMsgNotFound() *MsgNotFound {
- return &MsgNotFound{
- InvList: make([]*InvVect, 0, defaultInvListAlloc),
- }
- }
- type MsgPing struct {
- Nonce uint64
- }
- func (msg *MsgPing) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver > BIP0031Version {
- err := readElement(r, &msg.Nonce)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgPing) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver > BIP0031Version {
- err := writeElement(w, msg.Nonce)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgPing) Command() string {
- return CmdPing
- }
- func (msg *MsgPing) MaxPayloadLength(pver uint32) uint32 {
- plen := uint32(0)
- if pver > BIP0031Version {
- plen += 8
- }
- return plen
- }
- func NewMsgPing(nonce uint64) *MsgPing {
- return &MsgPing{
- Nonce: nonce,
- }
- }
- type MsgPong struct {
- Nonce uint64
- }
- func (msg *MsgPong) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver <= BIP0031Version {
- str := fmt.Sprintf("pong message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgPong.BtcDecode", str)
- }
- return readElement(r, &msg.Nonce)
- }
- func (msg *MsgPong) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver <= BIP0031Version {
- str := fmt.Sprintf("pong message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgPong.BtcEncode", str)
- }
- return writeElement(w, msg.Nonce)
- }
- func (msg *MsgPong) Command() string {
- return CmdPong
- }
- func (msg *MsgPong) MaxPayloadLength(pver uint32) uint32 {
- plen := uint32(0)
- if pver > BIP0031Version {
- plen += 8
- }
- return plen
- }
- func NewMsgPong(nonce uint64) *MsgPong {
- return &MsgPong{
- Nonce: nonce,
- }
- }
- type RejectCode uint8
- const (
- RejectMalformed RejectCode = 0x01
- RejectInvalid RejectCode = 0x10
- RejectObsolete RejectCode = 0x11
- RejectDuplicate RejectCode = 0x12
- RejectNonstandard RejectCode = 0x40
- RejectDust RejectCode = 0x41
- RejectInsufficientFee RejectCode = 0x42
- RejectCheckpoint RejectCode = 0x43
- )
- var rejectCodeStrings = map[RejectCode]string{
- RejectMalformed: "REJECT_MALFORMED",
- RejectInvalid: "REJECT_INVALID",
- RejectObsolete: "REJECT_OBSOLETE",
- RejectDuplicate: "REJECT_DUPLICATE",
- RejectNonstandard: "REJECT_NONSTANDARD",
- RejectDust: "REJECT_DUST",
- RejectInsufficientFee: "REJECT_INSUFFICIENTFEE",
- RejectCheckpoint: "REJECT_CHECKPOINT",
- }
- func (code RejectCode) String() string {
- if s, ok := rejectCodeStrings[code]; ok {
- return s
- }
- return fmt.Sprintf("Unknown RejectCode (%d)", uint8(code))
- }
- type MsgReject struct {
- Cmd string
- Code RejectCode
- Reason string
- Hash Hash
- }
- func (msg *MsgReject) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < RejectVersion {
- str := fmt.Sprintf("reject message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgReject.BtcDecode", str)
- }
- cmd, err := ReadVarString(r, pver)
- if err != nil {
- return err
- }
- msg.Cmd = cmd
- err = readElement(r, &msg.Code)
- if err != nil {
- return err
- }
- reason, err := ReadVarString(r, pver)
- if err != nil {
- return err
- }
- msg.Reason = reason
- if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
- err := readElement(r, &msg.Hash)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < RejectVersion {
- str := fmt.Sprintf("reject message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgReject.BtcEncode", str)
- }
- err := WriteVarString(w, pver, msg.Cmd)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.Code)
- if err != nil {
- return err
- }
- err = WriteVarString(w, pver, msg.Reason)
- if err != nil {
- return err
- }
- if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
- err := writeElement(w, &msg.Hash)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgReject) Command() string {
- return CmdReject
- }
- func (msg *MsgReject) MaxPayloadLength(pver uint32) uint32 {
- plen := uint32(0)
- if pver >= RejectVersion {
- plen = MaxMessagePayload
- }
- return plen
- }
- func NewMsgReject(command string, code RejectCode, reason string) *MsgReject {
- return &MsgReject{
- Cmd: command,
- Code: code,
- Reason: reason,
- }
- }
- type MsgSendHeaders struct{}
- func (msg *MsgSendHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- if pver < SendHeadersVersion {
- str := fmt.Sprintf("sendheaders message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgSendHeaders.BtcDecode", str)
- }
- return nil
- }
- func (msg *MsgSendHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- if pver < SendHeadersVersion {
- str := fmt.Sprintf("sendheaders message invalid for protocol "+
- "version %d", pver)
- return messageError("MsgSendHeaders.BtcEncode", str)
- }
- return nil
- }
- func (msg *MsgSendHeaders) Command() string {
- return CmdSendHeaders
- }
- func (msg *MsgSendHeaders) MaxPayloadLength(pver uint32) uint32 {
- return 0
- }
- func NewMsgSendHeaders() *MsgSendHeaders {
- return &MsgSendHeaders{}
- }
- const (
- TxVersion = 1
- MaxTxInSequenceNum uint32 = 0xffffffff
- MaxPrevOutIndex uint32 = 0xffffffff
- SequenceLockTimeDisabled = 1 << 31
- SequenceLockTimeIsSeconds = 1 << 22
- SequenceLockTimeMask = 0x0000ffff
- SequenceLockTimeGranularity = 9
- defaultTxInOutAlloc = 15
- minTxInPayload = 9 + HashSize
- maxTxInPerMessage = (MaxMessagePayload / minTxInPayload) + 1
- MinTxOutPayload = 9
- maxTxOutPerMessage = (MaxMessagePayload / MinTxOutPayload) + 1
- minTxPayload = 10
- freeListMaxScriptSize = 512
- freeListMaxItems = 12500
- maxWitnessItemsPerInput = 500000
- maxWitnessItemSize = 11000
- )
- const TxFlagMarker = 0x00
- type TxFlag = byte
- const (
- WitnessFlag TxFlag = 0x01
- )
- type scriptFreeList chan []byte
- func (c scriptFreeList) Borrow(size uint64) []byte {
- if size > freeListMaxScriptSize {
- return make([]byte, size)
- }
- var buf []byte
- select {
- case buf = <-c:
- default:
- buf = make([]byte, freeListMaxScriptSize)
- }
- return buf[:size]
- }
- func (c scriptFreeList) Return(buf []byte) {
- if cap(buf) != freeListMaxScriptSize {
- return
- }
- select {
- case c <- buf:
- default:
- }
- }
- var scriptPool scriptFreeList = make(chan []byte, freeListMaxItems)
- type OutPoint struct {
- Hash Hash
- Index uint32
- }
- func NewOutPoint(hash *Hash, index uint32) *OutPoint {
- return &OutPoint{
- Hash: *hash,
- Index: index,
- }
- }
- func (o OutPoint) String() string {
- buf := make([]byte, 2*HashSize+1, 2*HashSize+1+10)
- copy(buf, o.Hash.String())
- buf[2*HashSize] = ':'
- buf = strconv.AppendUint(buf, uint64(o.Index), 10)
- return string(buf)
- }
- type TxIn struct {
- PreviousOutPoint OutPoint
- SignatureScript []byte
- Witness TxWitness
- Sequence uint32
- }
- func (t *TxIn) SerializeSize() int {
- return 40 + VarIntSerializeSize(uint64(len(t.SignatureScript))) +
- len(t.SignatureScript)
- }
- func NewTxIn(prevOut *OutPoint, signatureScript []byte, witness [][]byte) *TxIn {
- return &TxIn{
- PreviousOutPoint: *prevOut,
- SignatureScript: signatureScript,
- Witness: witness,
- Sequence: MaxTxInSequenceNum,
- }
- }
- type TxWitness [][]byte
- func (t TxWitness) SerializeSize() int {
- n := VarIntSerializeSize(uint64(len(t)))
- for _, witItem := range t {
- n += VarIntSerializeSize(uint64(len(witItem)))
- n += len(witItem)
- }
- return n
- }
- type TxOut struct {
- Value int64
- PkScript []byte
- }
- func (t *TxOut) SerializeSize() int {
- return 8 + VarIntSerializeSize(uint64(len(t.PkScript))) + len(t.PkScript)
- }
- func NewTxOut(value int64, pkScript []byte) *TxOut {
- return &TxOut{
- Value: value,
- PkScript: pkScript,
- }
- }
- type MsgTx struct {
- Version int32
- TxIn []*TxIn
- TxOut []*TxOut
- LockTime uint32
- }
- func (msg *MsgTx) AddTxIn(ti *TxIn) {
- msg.TxIn = append(msg.TxIn, ti)
- }
- func (msg *MsgTx) AddTxOut(to *TxOut) {
- msg.TxOut = append(msg.TxOut, to)
- }
- func (msg *MsgTx) TxHash() Hash {
- buf := bytes.NewBuffer(make([]byte, 0, msg.SerializeSizeStripped()))
- _ = msg.SerializeNoWitness(buf)
- return DoubleHashH(buf.Bytes())
- }
- func (msg *MsgTx) WitnessHash() Hash {
- if msg.HasWitness() {
- buf := bytes.NewBuffer(make([]byte, 0, msg.SerializeSize()))
- _ = msg.Serialize(buf)
- return DoubleHashH(buf.Bytes())
- }
- return msg.TxHash()
- }
- func (msg *MsgTx) Copy() *MsgTx {
- newTx := MsgTx{
- Version: msg.Version,
- TxIn: make([]*TxIn, 0, len(msg.TxIn)),
- TxOut: make([]*TxOut, 0, len(msg.TxOut)),
- LockTime: msg.LockTime,
- }
- for _, oldTxIn := range msg.TxIn {
- oldOutPoint := oldTxIn.PreviousOutPoint
- newOutPoint := OutPoint{}
- newOutPoint.Hash.SetBytes(oldOutPoint.Hash[:])
- newOutPoint.Index = oldOutPoint.Index
- var newScript []byte
- oldScript := oldTxIn.SignatureScript
- oldScriptLen := len(oldScript)
- if oldScriptLen > 0 {
- newScript = make([]byte, oldScriptLen)
- copy(newScript, oldScript[:oldScriptLen])
- }
- newTxIn := TxIn{
- PreviousOutPoint: newOutPoint,
- SignatureScript: newScript,
- Sequence: oldTxIn.Sequence,
- }
- if len(oldTxIn.Witness) != 0 {
- newTxIn.Witness = make([][]byte, len(oldTxIn.Witness))
- for i, oldItem := range oldTxIn.Witness {
- newItem := make([]byte, len(oldItem))
- copy(newItem, oldItem)
- newTxIn.Witness[i] = newItem
- }
- }
- newTx.TxIn = append(newTx.TxIn, &newTxIn)
- }
- for _, oldTxOut := range msg.TxOut {
- var newScript []byte
- oldScript := oldTxOut.PkScript
- oldScriptLen := len(oldScript)
- if oldScriptLen > 0 {
- newScript = make([]byte, oldScriptLen)
- copy(newScript, oldScript[:oldScriptLen])
- }
- newTxOut := TxOut{
- Value: oldTxOut.Value,
- PkScript: newScript,
- }
- newTx.TxOut = append(newTx.TxOut, &newTxOut)
- }
- return &newTx
- }
- func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- version, err := binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- return err
- }
- msg.Version = int32(version)
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- var flag [1]TxFlag
- if count == TxFlagMarker && enc == WitnessEncoding {
- if _, err = io.ReadFull(r, flag[:]); err != nil {
- return err
- }
- if flag[0] != WitnessFlag {
- str := fmt.Sprintf("witness tx but flag byte is %x", flag)
- return messageError("MsgTx.BtcDecode", str)
- }
- count, err = ReadVarInt(r, pver)
- if err != nil {
- return err
- }
- }
- if count > uint64(maxTxInPerMessage) {
- str := fmt.Sprintf("too many input transactions to fit into "+
- "max message size [count %d, max %d]", count,
- maxTxInPerMessage)
- return messageError("MsgTx.BtcDecode", str)
- }
- returnScriptBuffers := func() {
- for _, txIn := range msg.TxIn {
- if txIn == nil {
- continue
- }
- if txIn.SignatureScript != nil {
- scriptPool.Return(txIn.SignatureScript)
- }
- for _, witnessElem := range txIn.Witness {
- if witnessElem != nil {
- scriptPool.Return(witnessElem)
- }
- }
- }
- for _, txOut := range msg.TxOut {
- if txOut == nil || txOut.PkScript == nil {
- continue
- }
- scriptPool.Return(txOut.PkScript)
- }
- }
- var totalScriptSize uint64
- txIns := make([]TxIn, count)
- msg.TxIn = make([]*TxIn, count)
- for i := uint64(0); i < count; i++ {
- ti := &txIns[i]
- msg.TxIn[i] = ti
- err = readTxIn(r, pver, msg.Version, ti)
- if err != nil {
- returnScriptBuffers()
- return err
- }
- totalScriptSize += uint64(len(ti.SignatureScript))
- }
- count, err = ReadVarInt(r, pver)
- if err != nil {
- returnScriptBuffers()
- return err
- }
- if count > uint64(maxTxOutPerMessage) {
- returnScriptBuffers()
- str := fmt.Sprintf("too many output transactions to fit into "+
- "max message size [count %d, max %d]", count,
- maxTxOutPerMessage)
- return messageError("MsgTx.BtcDecode", str)
- }
- txOuts := make([]TxOut, count)
- msg.TxOut = make([]*TxOut, count)
- for i := uint64(0); i < count; i++ {
- to := &txOuts[i]
- msg.TxOut[i] = to
- err = readTxOut(r, pver, msg.Version, to)
- if err != nil {
- returnScriptBuffers()
- return err
- }
- totalScriptSize += uint64(len(to.PkScript))
- }
- if flag[0] != 0 && enc == WitnessEncoding {
- for _, txin := range msg.TxIn {
- witCount, err := ReadVarInt(r, pver)
- if err != nil {
- returnScriptBuffers()
- return err
- }
- if witCount > maxWitnessItemsPerInput {
- returnScriptBuffers()
- str := fmt.Sprintf("too many witness items to fit "+
- "into max message size [count %d, max %d]",
- witCount, maxWitnessItemsPerInput)
- return messageError("MsgTx.BtcDecode", str)
- }
- txin.Witness = make([][]byte, witCount)
- for j := uint64(0); j < witCount; j++ {
- txin.Witness[j], err = readScript(r, pver,
- maxWitnessItemSize, "script witness item")
- if err != nil {
- returnScriptBuffers()
- return err
- }
- totalScriptSize += uint64(len(txin.Witness[j]))
- }
- }
- }
- msg.LockTime, err = binarySerializer.Uint32(r, littleEndian)
- if err != nil {
- returnScriptBuffers()
- return err
- }
- var offset uint64
- scripts := make([]byte, totalScriptSize)
- for i := 0; i < len(msg.TxIn); i++ {
- signatureScript := msg.TxIn[i].SignatureScript
- copy(scripts[offset:], signatureScript)
- scriptSize := uint64(len(signatureScript))
- end := offset + scriptSize
- msg.TxIn[i].SignatureScript = scripts[offset:end:end]
- offset += scriptSize
- scriptPool.Return(signatureScript)
- for j := 0; j < len(msg.TxIn[i].Witness); j++ {
- witnessElem := msg.TxIn[i].Witness[j]
- copy(scripts[offset:], witnessElem)
- witnessElemSize := uint64(len(witnessElem))
- end := offset + witnessElemSize
- msg.TxIn[i].Witness[j] = scripts[offset:end:end]
- offset += witnessElemSize
- scriptPool.Return(witnessElem)
- }
- }
- for i := 0; i < len(msg.TxOut); i++ {
- pkScript := msg.TxOut[i].PkScript
- copy(scripts[offset:], pkScript)
- scriptSize := uint64(len(pkScript))
- end := offset + scriptSize
- msg.TxOut[i].PkScript = scripts[offset:end:end]
- offset += scriptSize
- scriptPool.Return(pkScript)
- }
- return nil
- }
- func (msg *MsgTx) Deserialize(r io.Reader) error {
- return msg.BtcDecode(r, 0, WitnessEncoding)
- }
- func (msg *MsgTx) DeserializeNoWitness(r io.Reader) error {
- return msg.BtcDecode(r, 0, BaseEncoding)
- }
- func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- err := binarySerializer.PutUint32(w, littleEndian, uint32(msg.Version))
- if err != nil {
- return err
- }
- doWitness := enc == WitnessEncoding && msg.HasWitness()
- if doWitness {
- if _, err := w.Write([]byte{TxFlagMarker, WitnessFlag}); err != nil {
- return err
- }
- }
- count := uint64(len(msg.TxIn))
- err = WriteVarInt(w, pver, count)
- if err != nil {
- return err
- }
- for _, ti := range msg.TxIn {
- err = writeTxIn(w, pver, msg.Version, ti)
- if err != nil {
- return err
- }
- }
- count = uint64(len(msg.TxOut))
- err = WriteVarInt(w, pver, count)
- if err != nil {
- return err
- }
- for _, to := range msg.TxOut {
- err = WriteTxOut(w, pver, msg.Version, to)
- if err != nil {
- return err
- }
- }
- if doWitness {
- for _, ti := range msg.TxIn {
- err = writeTxWitness(w, pver, msg.Version, ti.Witness)
- if err != nil {
- return err
- }
- }
- }
- return binarySerializer.PutUint32(w, littleEndian, msg.LockTime)
- }
- func (msg *MsgTx) HasWitness() bool {
- for _, txIn := range msg.TxIn {
- if len(txIn.Witness) != 0 {
- return true
- }
- }
- return false
- }
- func (msg *MsgTx) Serialize(w io.Writer) error {
- return msg.BtcEncode(w, 0, WitnessEncoding)
- }
- func (msg *MsgTx) SerializeNoWitness(w io.Writer) error {
- return msg.BtcEncode(w, 0, BaseEncoding)
- }
- func (msg *MsgTx) baseSize() int {
- n := 8 + VarIntSerializeSize(uint64(len(msg.TxIn))) +
- VarIntSerializeSize(uint64(len(msg.TxOut)))
- for _, txIn := range msg.TxIn {
- n += txIn.SerializeSize()
- }
- for _, txOut := range msg.TxOut {
- n += txOut.SerializeSize()
- }
- return n
- }
- func (msg *MsgTx) SerializeSize() int {
- n := msg.baseSize()
- if msg.HasWitness() {
- n += 2
- for _, txin := range msg.TxIn {
- n += txin.Witness.SerializeSize()
- }
- }
- return n
- }
- func (msg *MsgTx) SerializeSizeStripped() int {
- return msg.baseSize()
- }
- func (msg *MsgTx) Command() string {
- return CmdTx
- }
- func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 {
- return MaxBlockPayload
- }
- func (msg *MsgTx) PkScriptLocs() []int {
- numTxOut := len(msg.TxOut)
- if numTxOut == 0 {
- return nil
- }
- n := 4 + VarIntSerializeSize(uint64(len(msg.TxIn))) +
- VarIntSerializeSize(uint64(numTxOut))
- if len(msg.TxIn) > 0 && msg.TxIn[0].Witness != nil {
- n += 2
- }
- for _, txIn := range msg.TxIn {
- n += txIn.SerializeSize()
- }
- pkScriptLocs := make([]int, numTxOut)
- for i, txOut := range msg.TxOut {
- n += 8 + VarIntSerializeSize(uint64(len(txOut.PkScript)))
- pkScriptLocs[i] = n
- n += len(txOut.PkScript)
- }
- return pkScriptLocs
- }
- func NewMsgTx(version int32) *MsgTx {
- return &MsgTx{
- Version: version,
- TxIn: make([]*TxIn, 0, defaultTxInOutAlloc),
- TxOut: make([]*TxOut, 0, defaultTxInOutAlloc),
- }
- }
- func readOutPoint(r io.Reader, pver uint32, version int32, op *OutPoint) error {
- _, err := io.ReadFull(r, op.Hash[:])
- if err != nil {
- return err
- }
- op.Index, err = binarySerializer.Uint32(r, littleEndian)
- return err
- }
- func writeOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error {
- _, err := w.Write(op.Hash[:])
- if err != nil {
- return err
- }
- return binarySerializer.PutUint32(w, littleEndian, op.Index)
- }
- func readScript(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) ([]byte, error) {
- count, err := ReadVarInt(r, pver)
- if err != nil {
- return nil, err
- }
- if count > uint64(maxAllowed) {
- str := fmt.Sprintf("%s is larger than the max allowed size "+
- "[count %d, max %d]", fieldName, count, maxAllowed)
- return nil, messageError("readScript", str)
- }
- b := scriptPool.Borrow(count)
- _, err = io.ReadFull(r, b)
- if err != nil {
- scriptPool.Return(b)
- return nil, err
- }
- return b, nil
- }
- func readTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error {
- err := readOutPoint(r, pver, version, &ti.PreviousOutPoint)
- if err != nil {
- return err
- }
- ti.SignatureScript, err = readScript(r, pver, MaxMessagePayload,
- "transaction input signature script")
- if err != nil {
- return err
- }
- return readElement(r, &ti.Sequence)
- }
- func writeTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error {
- err := writeOutPoint(w, pver, version, &ti.PreviousOutPoint)
- if err != nil {
- return err
- }
- err = WriteVarBytes(w, pver, ti.SignatureScript)
- if err != nil {
- return err
- }
- return binarySerializer.PutUint32(w, littleEndian, ti.Sequence)
- }
- func readTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error {
- err := readElement(r, &to.Value)
- if err != nil {
- return err
- }
- to.PkScript, err = readScript(r, pver, MaxMessagePayload,
- "transaction output public key script")
- return err
- }
- func WriteTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error {
- err := binarySerializer.PutUint64(w, littleEndian, uint64(to.Value))
- if err != nil {
- return err
- }
- return WriteVarBytes(w, pver, to.PkScript)
- }
- func writeTxWitness(w io.Writer, pver uint32, version int32, wit [][]byte) error {
- err := WriteVarInt(w, pver, uint64(len(wit)))
- if err != nil {
- return err
- }
- for _, item := range wit {
- err = WriteVarBytes(w, pver, item)
- if err != nil {
- return err
- }
- }
- return nil
- }
- type MsgVerAck struct{}
- func (msg *MsgVerAck) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- return nil
- }
- func (msg *MsgVerAck) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- return nil
- }
- func (msg *MsgVerAck) Command() string {
- return CmdVerAck
- }
- func (msg *MsgVerAck) MaxPayloadLength(pver uint32) uint32 {
- return 0
- }
- func NewMsgVerAck() *MsgVerAck {
- return &MsgVerAck{}
- }
- const MaxUserAgentLen = 256
- const DefaultUserAgent = "/btc0.5.0/"
- type MsgVersion struct {
- ProtocolVersion int32
- Services ServiceFlag
- Timestamp time.Time
- AddrYou NetAddress
- AddrMe NetAddress
- Nonce uint64
- UserAgent string
- LastBlock int32
- DisableRelayTx bool
- }
- func (msg *MsgVersion) HasService(service ServiceFlag) bool {
- return msg.Services&service == service
- }
- func (msg *MsgVersion) AddService(service ServiceFlag) {
- msg.Services |= service
- }
- func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- buf, ok := r.(*bytes.Buffer)
- if !ok {
- return fmt.Errorf("MsgVersion.BtcDecode reader is not a " +
- "*bytes.Buffer")
- }
- err := readElements(buf, &msg.ProtocolVersion, &msg.Services,
- (*int64Time)(&msg.Timestamp))
- if err != nil {
- return err
- }
- err = readNetAddress(buf, pver, &msg.AddrYou, false)
- if err != nil {
- return err
- }
- if buf.Len() > 0 {
- err = readNetAddress(buf, pver, &msg.AddrMe, false)
- if err != nil {
- return err
- }
- }
- if buf.Len() > 0 {
- err = readElement(buf, &msg.Nonce)
- if err != nil {
- return err
- }
- }
- if buf.Len() > 0 {
- userAgent, err := ReadVarString(buf, pver)
- if err != nil {
- return err
- }
- err = validateUserAgent(userAgent)
- if err != nil {
- return err
- }
- msg.UserAgent = userAgent
- }
- if buf.Len() > 0 {
- err = readElement(buf, &msg.LastBlock)
- if err != nil {
- return err
- }
- }
- if buf.Len() > 0 {
- var relayTx bool
- readElement(r, &relayTx)
- msg.DisableRelayTx = !relayTx
- }
- return nil
- }
- func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- err := validateUserAgent(msg.UserAgent)
- if err != nil {
- return err
- }
- err = writeElements(w, msg.ProtocolVersion, msg.Services,
- msg.Timestamp.Unix())
- if err != nil {
- return err
- }
- err = writeNetAddress(w, pver, &msg.AddrYou, false)
- if err != nil {
- return err
- }
- err = writeNetAddress(w, pver, &msg.AddrMe, false)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.Nonce)
- if err != nil {
- return err
- }
- err = WriteVarString(w, pver, msg.UserAgent)
- if err != nil {
- return err
- }
- err = writeElement(w, msg.LastBlock)
- if err != nil {
- return err
- }
- if pver >= BIP0037Version {
- err = writeElement(w, !msg.DisableRelayTx)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (msg *MsgVersion) Command() string {
- return CmdVersion
- }
- func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 {
- return 33 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload +
- MaxUserAgentLen
- }
- func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
- lastBlock int32) *MsgVersion {
- return &MsgVersion{
- ProtocolVersion: int32(ProtocolVersion),
- Services: 0,
- Timestamp: time.Unix(time.Now().Unix(), 0),
- AddrYou: *you,
- AddrMe: *me,
- Nonce: nonce,
- UserAgent: DefaultUserAgent,
- LastBlock: lastBlock,
- DisableRelayTx: false,
- }
- }
- func validateUserAgent(userAgent string) error {
- if len(userAgent) > MaxUserAgentLen {
- str := fmt.Sprintf("user agent too long [len %v, max %v]",
- len(userAgent), MaxUserAgentLen)
- return messageError("MsgVersion", str)
- }
- return nil
- }
- func (msg *MsgVersion) AddUserAgent(name string, version string,
- comments ...string) error {
- newUserAgent := fmt.Sprintf("%s:%s", name, version)
- if len(comments) != 0 {
- newUserAgent = fmt.Sprintf("%s(%s)", newUserAgent,
- strings.Join(comments, "; "))
- }
- newUserAgent = fmt.Sprintf("%s%s/", msg.UserAgent, newUserAgent)
- err := validateUserAgent(newUserAgent)
- if err != nil {
- return err
- }
- msg.UserAgent = newUserAgent
- return nil
- }
- var myMutex sync.RWMutex
- var myChain map[uint64]*Hash
- var myHeaders map[Hash]*BlockHeader
- var myTotal uint64
- func init() {
- myChain = make(map[uint64]*Hash)
- myHeaders = make(map[Hash]*BlockHeader)
- }
- func myPut(bh *Hash, height uint64) {
- myMutex.Lock()
- if height == myTotal {
- myChain[height] = bh
- }
- myMutex.Unlock()
- }
- func myGet(height uint64) (bh *Hash) {
- myMutex.RLock()
- bh = myChain[height]
- myMutex.RUnlock()
- return bh
- }
- func myHas(bh *Hash) (has bool) {
- myMutex.RLock()
- has = myHeaders[*bh] != nil
- myMutex.RUnlock()
- return has
- }
- func myGoodReorg(h uint64, depth uint64, bh *BlockHeader) bool {
- return h >= depth && bh != nil
- }
- func myAttach(bh *BlockHeader, reorg func(a, b *Hash)) {
- hash := bh.BlockHash()
- myMutex.Lock()
- myHeaders[hash] = bh
- if current, ok := myChain[myTotal]; ok && *current == bh.PrevBlock {
- myTotal++
- myChain[myTotal] = &hash
- }
- var reorg1 = myHeaders[bh.PrevBlock]
- if myGoodReorg(myTotal, 1, reorg1) {
- if current, ok := myChain[myTotal-1]; ok && *current == reorg1.PrevBlock {
- delete(myChain, myTotal)
- myTotal--
- myChain[myTotal] = &bh.PrevBlock
- reorg(&bh.PrevBlock, &hash)
- myTotal++
- myChain[myTotal] = &hash
- }
- }
- myMutex.Unlock()
- }
- func myTotalBlocksEstimate() int64 {
- myMutex.RLock()
- var tot = myTotal
- myMutex.RUnlock()
- const NOW_TIME = 1602787294
- const NOW_BLOCKS = 652888
- if tot < NOW_BLOCKS {
- return NOW_BLOCKS + ((time.Now().Unix() - NOW_TIME) / 600)
- } else {
- myMutex.RLock()
- var blk = myHeaders[*myChain[tot]]
- var blktime = blk.Timestamp
- myMutex.RUnlock()
- return int64(tot + ((uint64(time.Now().Unix()) - uint64(blktime.Unix())) / 600))
- }
- }
- func myStatus(fun func(tot uint64, hsh *Hash)) uint64 {
- myMutex.RLock()
- var tot = myTotal
- var hsh = myChain[myTotal]
- if fun != nil {
- fun(tot, hsh)
- }
- myMutex.RUnlock()
- return tot
- }
- func myLocator(burst, depth byte, fun func(uint64, *Hash)) {
- myMutex.RLock()
- var i = int64(myTotal) - int64(depth)
- if i < 0 {
- i = 0
- }
- myMutex.RUnlock()
- myLocatorHeight(i, burst, fun)
- }
- func myLocatorHeight(i int64, burst byte, fun func(uint64, *Hash)) {
- for j := i; j > i-int64(burst) && j >= 0; j-- {
- myMutex.RLock()
- hash := myChain[uint64(j)]
- myMutex.RUnlock()
- fun(uint64(j), hash)
- }
- var k int64 = 2
- for j := i - int64(burst) - 1; j >= 0; j -= k {
- k *= 2
- myMutex.RLock()
- hash := myChain[uint64(j)]
- myMutex.RUnlock()
- fun(uint64(j), hash)
- }
- }
- func maxNetAddressPayload(pver uint32) uint32 {
- plen := uint32(26)
- if pver >= NetAddressTimeVersion {
- plen += 4
- }
- return plen
- }
- type NetAddress struct {
- Timestamp time.Time
- Services ServiceFlag
- IP net.IP
- Port uint16
- }
- func (na *NetAddress) HasService(service ServiceFlag) bool {
- return na.Services&service == service
- }
- func (na *NetAddress) AddService(service ServiceFlag) {
- na.Services |= service
- }
- func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
- return NewNetAddressTimestamp(time.Now(), services, ip, port)
- }
- func NewNetAddressTimestamp(
- timestamp time.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress {
- na := NetAddress{
- Timestamp: time.Unix(timestamp.Unix(), 0),
- Services: services,
- IP: ip,
- Port: port,
- }
- return &na
- }
- func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
- return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services)
- }
- func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
- var ip [16]byte
- if ts && pver >= NetAddressTimeVersion {
- err := readElement(r, (*uint32Time)(&na.Timestamp))
- if err != nil {
- return err
- }
- }
- err := readElements(r, &na.Services, &ip)
- if err != nil {
- return err
- }
- port, err := binarySerializer.Uint16(r, bigEndian)
- if err != nil {
- return err
- }
- *na = NetAddress{
- Timestamp: na.Timestamp,
- Services: na.Services,
- IP: net.IP(ip[:]),
- Port: port,
- }
- return nil
- }
- func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
- if ts && pver >= NetAddressTimeVersion {
- err := writeElement(w, uint32(na.Timestamp.Unix()))
- if err != nil {
- return err
- }
- }
- var ip [16]byte
- if na.IP != nil {
- copy(ip[:], na.IP.To16())
- }
- err := writeElements(w, na.Services, ip)
- if err != nil {
- return err
- }
- return binary.Write(w, bigEndian, na.Port)
- }
- var previously_seen_mutex sync.Mutex
- var previously_seen map[[32]byte]struct{}
- func init() {
- previously_seen_mutex.Lock()
- previously_seen = make(map[[32]byte]struct{})
- previously_seen_mutex.Unlock()
- }
- func is_previously_unseen_make_seen(hash *[32]byte) bool {
- previously_seen_mutex.Lock()
- if _, ok := previously_seen[*hash]; ok {
- previously_seen_mutex.Unlock()
- return false
- } else {
- previously_seen[*hash] = struct{}{}
- previously_seen_mutex.Unlock()
- return true
- }
- }
- type Bar struct {
- percent int64
- beg int64
- cur int64
- total int64
- rate string
- Graph string
- Unit string
- }
- func (bar *Bar) getPercent() int64 {
- if bar.total == bar.beg {
- return 0
- }
- return 100 * (bar.cur - bar.beg) / (bar.total - bar.beg)
- }
- func (bar *Bar) Replay() {
- bar.Play(bar.beg, bar.cur, bar.total)
- }
- func (bar *Bar) Play(beg, cur, total int64) {
- fmt.Print("\r")
- bar.play(beg, cur, total)
- }
- func (bar *Bar) play(beg, cur, total int64) {
- bar.beg = beg
- bar.cur = cur
- bar.total = total
- last := bar.percent
- bar.percent = bar.getPercent()
- if bar.percent != last && bar.percent%2 == 0 {
- bar.rate += bar.Graph
- }
- fmt.Printf("[%-50s]%3d%% %8d/%d %s", bar.rate, bar.percent, bar.cur, bar.total, bar.Unit)
- }
- func (bar *Bar) Hide() {
- fmt.Print("\r\x1B[K\r")
- }
- func (bar *Bar) Finish() {
- fmt.Println("")
- }
- func (bar *Bar) Restart(unit string) {
- bar.rate = ""
- bar.Unit = unit
- }
- const (
- ProtocolVersion uint32 = 70013
- MultipleAddressVersion uint32 = 209
- NetAddressTimeVersion uint32 = 31402
- BIP0031Version uint32 = 60000
- BIP0035Version uint32 = 60002
- BIP0037Version uint32 = 70001
- RejectVersion uint32 = 70002
- BIP0111Version uint32 = 70011
- SendHeadersVersion uint32 = 70012
- FeeFilterVersion uint32 = 70013
- )
- type ServiceFlag uint64
- const (
- SFNodeNetwork ServiceFlag = 1 << iota
- SFNodeGetUTXO
- SFNodeBloom
- SFNodeWitness
- SFNodeXthin
- SFNodeBit5
- SFNodeCF
- SFNode2X
- )
- var sfStrings = map[ServiceFlag]string{
- SFNodeNetwork: "SFNodeNetwork",
- SFNodeGetUTXO: "SFNodeGetUTXO",
- SFNodeBloom: "SFNodeBloom",
- SFNodeWitness: "SFNodeWitness",
- SFNodeXthin: "SFNodeXthin",
- SFNodeBit5: "SFNodeBit5",
- SFNodeCF: "SFNodeCF",
- SFNode2X: "SFNode2X",
- }
- var orderedSFStrings = []ServiceFlag{
- SFNodeNetwork,
- SFNodeGetUTXO,
- SFNodeBloom,
- SFNodeWitness,
- SFNodeXthin,
- SFNodeBit5,
- SFNodeCF,
- SFNode2X,
- }
- func (f ServiceFlag) String() string {
- if f == 0 {
- return "0x0"
- }
- s := ""
- for _, flag := range orderedSFStrings {
- if f&flag == flag {
- s += sfStrings[flag] + "|"
- f -= flag
- }
- }
- s = strings.TrimRight(s, "|")
- if f != 0 {
- s += "|0x" + strconv.FormatUint(uint64(f), 16)
- }
- s = strings.TrimLeft(s, "|")
- return s
- }
- type BitcoinNet uint32
- const (
- MainNet BitcoinNet = 0xd9b4bef9
- TestNet BitcoinNet = 0xdab5bffa
- TestNet3 BitcoinNet = 0x0709110b
- SimNet BitcoinNet = 0x12141c16
- )
- var bnStrings = map[BitcoinNet]string{
- MainNet: "MainNet",
- TestNet: "TestNet",
- TestNet3: "TestNet3",
- SimNet: "SimNet",
- }
- func (n BitcoinNet) String() string {
- if s, ok := bnStrings[n]; ok {
- return s
- }
- return fmt.Sprintf("Unknown BitcoinNet (%d)", uint32(n))
- }
- var shutdown_mutex sync.Mutex
- var shutdown bool
- var shutdown_conn *net.Conn
- func SetupCloseHandler(conn *net.Conn) {
- shutdown_mutex.Lock()
- shutdown_conn = conn
- shutdown_mutex.Unlock()
- c := make(chan os.Signal)
- signal.Notify(c, os.Interrupt, syscall.SIGTERM)
- go func() {
- <-c
- shutdown_mutex.Lock()
- shutdown = true
- if shutdown_conn != nil {
- (*shutdown_conn).Close()
- shutdown_conn = nil
- }
- shutdown_mutex.Unlock()
- }()
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement