Beispiel #1
0
func (inv *Inventory) Run() {
	go func() {
		for {
			select {
			case _ = <-inv.closeCh:
				inv.headers.Close()
				inv.config.Database.Close()
				close(inv.doneCh)
				return
			case m, ok := <-inv.input:
				if !ok {
					log.Fatal("Inventory input channel closed.")
				}
				switch m.Type {
				case "version":
					inv.handleVersionMessage(m)
				case "inv":
					inv.handleInvMessage(m)
				case "tx":
					tx, err := messages.ParseTransaction(m.Data)
					if err != nil {
						log.Printf("Failed to parse transaction: %v", err)
					} else {
						inv.handleTransaction(tx)
					}
				case "merkleblock":
					inv.handleMerkleBlock(m)
				default:
					log.Fatalf("Inventory input channel sent message of type %q.",
						m.Type)
				}
			}
		}
	}()
}
func NewMockInventory() *MockInventory {
	tx1, _ := hex.DecodeString("0100000001ca9b66c45ab5d802eff79224806a2bdcd690309a4dfcd8650963d3cd606ceadf000000006b4830450220324de09f8f7c8908d4a4b99c13aa28d1a5b3b680a196e6e6d39255e2b4d126c802210089fed6635be470c33f717db1a44f89150ebad18ab511fcf176c959cef7a9c9420121032d9850b19296fe1077f28a3c64d957f5242367dc6d42595b7ca7ca1aaed3dd1dffffffff0250c30000000000001976a914fe2927160e030613c119fbc68bc9ab0576f5911888ace0220200000000001976a9145ee70c467c5b2c35d2d08ef0d6d202b9c917b26188ac00000000")
	tx2, _ := hex.DecodeString("010000000194db6f49d474a9522dca43d0d83fc243049ed15600b07be4a568a377a590358b000000006a473044022023b2d60ad177429271d5df08a228e43ae3d60b63a236ed271b539dd7a391a6f102204e49ff80f5d6e06274fcac83e99371a7e324ecb08efd631ffb6f6f8c5889189a0121026db91d30b5e4081e02ff952f8d6b4d5e4528bd6617ae02a9abd7a437af0b6c2cffffffff02400d0300000000001976a91466fb2649c17e60c4cd16a05c903a161a24aa11a688acf3005f02000000001976a9143f896aad85d7fd306348c5f650662ed9346b2d6788ac00000000")
	parsed1, err := messages.ParseTransaction(tx1)
	if err != nil {
		panic(fmt.Sprintf("Failed to parse tx: %v", err))
	}
	parsed2, err := messages.ParseTransaction(tx2)
	if err != nil {
		panic(fmt.Sprintf("Failed to parse tx: %v", err))
	}
	inv := &MockInventory{
		inv: make(map[string]*messages.Transaction),
	}
	inv.inv[string(parsed1.Hash())] = parsed1
	inv.inv[string(parsed2.Hash())] = parsed2
	return inv
}
Beispiel #3
0
func (t *TxVersion) DeserializeTransaction() error {
	if len(t.Data) > 0 && t.tx == nil {
		var err error
		t.tx, err = messages.ParseTransaction(t.Data)
		if err != nil {
			return fmt.Errorf("Failed to parse transaction: %v", err)
		}
	}
	return nil
}
Beispiel #4
0
func main() {
	flag.Parse()

	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)

	var i *inventory.Inventory
	var n *network.Network
	var d *network.Dispatcher
	output := make(chan network.Message)

	go func() {
		sig := <-sigs

		fmt.Println()
		fmt.Println(sig)

		t := time.NewTimer(2 * time.Second)
		go func() {
			_ = <-t.C
			log.Println("shut down timed out; forcing exit")
			os.Exit(2)
		}()

		i.Unsubscribe(d)
		i.Close()
		n.Close()
		d.Close()
		close(output)

		os.Exit(1)
	}()

	n = network.New(network.Config{
		DesiredConnections: *connections,
		PeerStorageFile:    *peerFile,
		SeedHostnames: []string{
			"bitseed.xf2.org",
			"dnsseed.bluematt.me",
			"seed.bitcoin.sipa.be",
			"dnsseed.bitcoin.dashjr.org",
			"seed.bitcoinstats.com",
		},
		OutputChannel: output,
	})

	config := inventory.Config{
		// TODO Set database path from parameter.
		Database: database.Open(),
		Network:  n,
	}
	if *walletSeed != "" {
		seed := mnemonic.SeedFromWordsPassword(
			strings.Split(*walletSeed, " "), "")
		key := hdkeys.NewMasterKey(seed)
		config.Wallet = wallet.New(key)
	}
	i = inventory.New(&config)
	if config.Wallet != nil {
		config.Wallet.SetTxInventory(i)
	}

	d = network.NewDispatcher(output)
	i.Subscribe(d)
	d.Run()
	i.Run()

	go func() {
		<-i.Connected()
		i.GetRecentMerkleBlocks(2000)
	}()

	sendPayment := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		r.ParseForm()
		if config.Wallet != nil {
			var transactions []*messages.Transaction
			txHexes := r.Form["tx"]
			if len(txHexes) > 0 {
				for _, txHex := range txHexes {
					txSer, err := hex.DecodeString(txHex)
					if err != nil {
						fmt.Fprintf(w, "Error parsing transaction hex %q: %v",
							txHex, err)
						return
					}
					tx, err := messages.ParseTransaction(txSer)
					if err != nil {
						fmt.Fprintf(w, "Error parsing transaction %x: %v",
							txSer, err)
						return
					}
					transactions = append(transactions, tx)
				}
			} else {

				addr, prefix, err := base58.BitcoinCheckDecode(r.FormValue("addr"))
				if err != nil || prefix != base58.BitcoinPublicKeyHashPrefix {
					fmt.Fprintf(w, "Error parsing addr %q: %v",
						r.FormValue("addr"), err)
					return
				}
				value, err := strconv.ParseUint(r.FormValue("value"), 10, 64)
				if err != nil {
					fmt.Fprintf(w, "Error parsing value %q: %v",
						r.FormValue("value"), err)
					return
				}
				payment := config.Wallet.NewPayment()
				err = payment.AddOutput(addr, value)
				if err != nil {
					fmt.Fprintf(w, "Error adding output: %v", err)
					return
				}
				err = payment.AddInputsAndFee(10000)
				if err != nil {
					fmt.Fprintf(w, "Error adding inputs: %v", err)
					return
				}
				err = payment.Sign()
				if err != nil {
					fmt.Fprintf(w, "Error signing transaction: %v", err)
					return
				}
				transactions = payment.Transactions()
			}
			if len(transactions) > 1 {
				fmt.Fprintf(w, "Using duplicate transactions to cope "+
					"with duplicate inputs.<br><br>")
			}
			for _, tx := range transactions {
				fmt.Fprintf(w, "<font face=\"courier\">Transaction: %s</font><br>",
					strings.Replace(tx.String(), "\n", "<br/>", -1))
				verified, err := i.VerifyTransaction(tx)
				if err != nil || !verified {
					fmt.Fprintf(w, "Error verifying transaction: %v", err)
					return
				}
				fmt.Fprintf(w, "<br><b>Signatures verified!</b><br><br>")
			}
			if r.FormValue("send") == "true" {
				for _, tx := range transactions {
					n.SendChannel() <- network.Message{
						Type: "tx",
						Data: tx.Data(),
					}
				}
				n.SendChannel() <- network.Message{
					Type: "mempool",
				}
			} else {
				str := "<br><br><a href=\"?"
				for _, tx := range transactions {
					str += fmt.Sprintf("tx=%x&", tx.Data())
				}
				str += "send=true\">Broadcast transaction(s)</a>"
				fmt.Fprintf(w, str)
			}
		} else {
			fmt.Fprintf(w, "No wallet configured.")
		}
	}

	http.Handle("/peers", n)
	http.Handle("/inventory/", i)
	http.HandleFunc("/send/payment", sendPayment)
	log.Fatal(http.ListenAndServe(":8080", nil))
}