// Get tx with given id from the balance folder, of from cache func tx_from_balance(txid *btc.Uint256, error_is_fatal bool) (tx *btc.Tx) { if tx = loadedTxs[txid.Hash]; tx != nil { return // we have it in cache already } fn := "balance/" + txid.String() + ".tx" buf, er := ioutil.ReadFile(fn) if er == nil && buf != nil { var th [32]byte btc.ShaHash(buf, th[:]) if txid.Hash == th { tx, _ = btc.NewTx(buf) if error_is_fatal && tx == nil { println("Transaction is corrupt:", txid.String()) cleanExit(1) } } else if error_is_fatal { println("Transaction file is corrupt:", txid.String()) cleanExit(1) } } else if error_is_fatal { println("Error reading transaction file:", fn) if er != nil { println(er.Error()) } cleanExit(1) } loadedTxs[txid.Hash] = tx // store it in the cache return }
func execute_test_tx(t *testing.T, tv *testvector) bool { if len(tv.inps) == 0 { t.Error("Vector has no inputs") return false } rd, er := hex.DecodeString(tv.tx) if er != nil { t.Error(er.Error()) return false } tx, _ := btc.NewTx(rd) if tx == nil { t.Error("Canot decode tx") return false } tx.Size = uint32(len(rd)) ha := btc.Sha2Sum(rd) tx.Hash = btc.NewUint256(ha[:]) if skip_broken_tests(tx) { return false } oks := 0 for i := range tx.TxIn { var j int for j = range tv.inps { if bytes.Equal(tx.TxIn[i].Input.Hash[:], tv.inps[j].txid.Hash[:]) && tx.TxIn[i].Input.Vout == uint32(tv.inps[j].vout) { break } } if j >= len(tv.inps) { t.Error("Matching input not found") continue } pk, er := btc.DecodeScript(tv.inps[j].pkscr) if er != nil { t.Error(er.Error()) continue } var ss []byte if tv.inps[j].vout >= 0 { ss = tx.TxIn[i].ScriptSig } if VerifyTxScript(ss, pk, i, tx, tv.ver_flags) { oks++ } } return oks == len(tx.TxIn) }
func raw_tx_from_file(fn string) *btc.Tx { dat := sys.GetRawData(fn) if dat == nil { fmt.Println("Cannot fetch raw transaction data") return nil } tx, txle := btc.NewTx(dat) if tx != nil { tx.Hash = btc.NewSha2Hash(dat) if txle != len(dat) { fmt.Println("WARNING: Raw transaction length mismatch", txle, len(dat)) } } return tx }
func raw_tx_from_file(fn string) *btc.Tx { d, er := ioutil.ReadFile(fn) if er != nil { fmt.Println(er.Error()) return nil } dat, er := hex.DecodeString(string(d)) if er != nil { fmt.Println("hex.DecodeString failed - assume binary transaction file") dat = d } tx, txle := btc.NewTx(dat) if tx != nil && txle != len(dat) { fmt.Println("WARNING: Raw transaction length mismatch", txle, len(dat)) } return tx }
func LoadRawTx(buf []byte) (s string) { txd, er := hex.DecodeString(string(buf)) if er != nil { txd = buf } // At this place we should have raw transaction in txd tx, le := btc.NewTx(txd) if tx == nil || le != len(txd) { s += fmt.Sprintln("Could not decode transaction file or it has some extra data") return } tx.Hash = btc.NewSha2Hash(txd) network.TxMutex.Lock() defer network.TxMutex.Unlock() if _, ok := network.TransactionsToSend[tx.Hash.BIdx()]; ok { s += fmt.Sprintln("TxID", tx.Hash.String(), "was already in the pool") return } var missinginp bool var totinp, totout uint64 s, missinginp, totinp, totout, er = DecodeTx(tx) if er != nil { return } if missinginp { network.TransactionsToSend[tx.Hash.BIdx()] = &network.OneTxToSend{Tx: tx, Data: txd, Own: 2, Firstseen: time.Now(), Volume: totout} } else { network.TransactionsToSend[tx.Hash.BIdx()] = &network.OneTxToSend{Tx: tx, Data: txd, Own: 1, Firstseen: time.Now(), Volume: totinp, Fee: totinp - totout} } s += fmt.Sprintln("Transaction added to the memory pool. Please double check its details above.") s += fmt.Sprintln("If it does what you intended, you can send it the network.\nUse TxID:", tx.Hash.String()) return }
func TestSighash(t *testing.T) { var arr [][]interface{} dat, er := ioutil.ReadFile("../test/sighash.json") if er != nil { println(er.Error()) return } r := bytes.NewBuffer(dat) d := json.NewDecoder(r) d.UseNumber() er = d.Decode(&arr) if er != nil { println(er.Error()) return } for i := range arr { if len(arr[i]) == 5 { tmp, _ := hex.DecodeString(arr[i][0].(string)) tx, _ := btc.NewTx(tmp) if tx == nil { t.Error("Cannot decode tx from text number", i) continue } tmp, _ = hex.DecodeString(arr[i][1].(string)) // script iidx, _ := arr[i][2].(json.Number).Int64() htype, _ := arr[i][3].(json.Number).Int64() got := tx.SignatureHash(tmp, int(iidx), int32(htype)) exp := btc.NewUint256FromString(arr[i][4].(string)) if !bytes.Equal(exp.Hash[:], got) { t.Error("SignatureHash mismatch at index", i) } } } }
// Handle incoming "tx" msg func (c *OneConnection) ParseTxNet(pl []byte) { tid := btc.NewSha2Hash(pl) NeedThisTx(tid, func() { // This body is called with a locked TxMutex if uint32(len(pl)) > atomic.LoadUint32(&common.CFG.TXPool.MaxTxSize) { common.CountSafe("TxRejectedBig") RejectTx(tid, len(pl), TX_REJECTED_TOO_BIG) return } tx, le := btc.NewTx(pl) if tx == nil { RejectTx(tid, len(pl), TX_REJECTED_FORMAT) c.DoS("TxRejectedBroken") return } if le != len(pl) { RejectTx(tid, len(pl), TX_REJECTED_LEN_MISMATCH) c.DoS("TxRejectedLenMismatch") return } if len(tx.TxIn) < 1 { RejectTx(tid, len(pl), TX_REJECTED_EMPTY_INPUT) c.Misbehave("TxRejectedNoInputs", 100) return } tx.Hash = tid select { case NetTxs <- &TxRcvd{conn: c, tx: tx, raw: pl}: TransactionsPending[tid.BIdx()] = true default: common.CountSafe("NetTxsFULL") println("NetTxsFULL") } }) }
func p_miners(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } common.ReloadMiners() m := make(map[string]omv, 20) var om omv cnt := 0 common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() var lastts int64 var diff float64 var totbts uint64 var totfees uint64 current_mid := -1 now := time.Now().Unix() common.LockCfg() minerid := common.CFG.Beeps.MinerID common.UnlockCfg() next_diff_change := 2016 - end.Height%2016 block_versions := make(map[uint32]uint) // bip100 bip100_voting := make(map[string]uint) //var bip100, bip100v uint64 bip100x := regexp.MustCompile("/BV{0,1}[0-9]+[M]{0,1}/") //bip100rx := regexp.MustCompile("/B[0-9]+[M]{0,1}/") for ; end != nil; cnt++ { if now-int64(end.Timestamp()) > int64(common.CFG.MiningStatHours)*3600 { break } lastts = int64(end.Timestamp()) bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return } block, e := btc.NewBlock(bl) cbasetx, _ := btc.NewTx(bl[block.TxOffset:]) block_versions[binary.LittleEndian.Uint32(bl[0:4])]++ diff += btc.GetDifficulty(end.Bits()) miner, mid := common.TxMiner(cbasetx) if mid == -1 { miner = "<i>" + miner + "</i>" } om = m[miner] om.cnt++ om.bts += uint64(len(bl)) om.mid = mid // Blocks reward var rew uint64 for o := range cbasetx.TxOut { rew += cbasetx.TxOut[o].Value } om.fees += rew - btc.GetBlockReward(end.Height) // bip-100 res := bip100x.Find(cbasetx.TxIn[0].ScriptSig) if res != nil { bip100_voting[string(res)]++ } m[miner] = om if mid != -1 && current_mid == -1 && minerid == string(common.MinerIds[mid].Tag) { current_mid = mid } totbts += uint64(len(bl)) end = end.Parent } if cnt == 0 { write_html_head(w, r) w.Write([]byte(fmt.Sprint("No blocks in last ", common.CFG.MiningStatHours, " hours"))) write_html_tail(w) return } srt := make(onemiernstat, len(m)) i := 0 for k, v := range m { srt[i].name = k srt[i].omv = v i++ } sort.Sort(srt) mnrs := load_template("miners.html") onerow := load_template("miners_row.html") diff /= float64(cnt) bph := float64(cnt) / float64(common.CFG.MiningStatHours) hrate := bph / 6 * diff * 7158278.826667 mnrs = strings.Replace(mnrs, "{MINING_HOURS}", fmt.Sprint(common.CFG.MiningStatHours), 1) mnrs = strings.Replace(mnrs, "{BLOCKS_COUNT}", fmt.Sprint(cnt), 1) mnrs = strings.Replace(mnrs, "{FIRST_BLOCK_TIME}", time.Unix(lastts, 0).Format("2006-01-02 15:04:05"), 1) mnrs = strings.Replace(mnrs, "{AVG_BLOCKS_PER_HOUR}", fmt.Sprintf("%.2f", bph), 1) mnrs = strings.Replace(mnrs, "{AVG_DIFFICULTY}", common.NumberToString(diff), 1) mnrs = strings.Replace(mnrs, "{AVG_HASHDATE}", common.HashrateToString(hrate), 1) mnrs = strings.Replace(mnrs, "{AVG_BLOCKSIZE}", fmt.Sprintf("%.1fKB", float64(totbts)/float64(cnt)/1000), 1) mnrs = strings.Replace(mnrs, "{DIFF_CHANGE_IN}", fmt.Sprint(next_diff_change), 1) mnrs = strings.Replace(mnrs, "{MINER_MON_IDX}", fmt.Sprint(current_mid), 1) for i := range srt { s := onerow s = strings.Replace(s, "{MINER_NAME}", srt[i].name, 1) s = strings.Replace(s, "{BLOCK_COUNT}", fmt.Sprint(srt[i].cnt), 1) s = strings.Replace(s, "{TOTAL_PERCENT}", fmt.Sprintf("%.0f", 100*float64(srt[i].cnt)/float64(cnt)), 1) s = strings.Replace(s, "{MINER_HASHRATE}", common.HashrateToString(hrate*float64(srt[i].cnt)/float64(cnt)), 1) s = strings.Replace(s, "{AVG_BLOCK_SIZE}", fmt.Sprintf("%.1fKB", float64(srt[i].bts)/float64(srt[i].cnt)/1000), 1) s = strings.Replace(s, "{MINER_ID}", fmt.Sprint(srt[i].mid), -1) s = strings.Replace(s, "<!--TOTAL_FEES-->", btc.UintToBtc(srt[i].fees), -1) s = strings.Replace(s, "<!--FEE_PER_BYTE-->", fmt.Sprint(srt[i].fees/srt[i].bts), -1) mnrs = templ_add(mnrs, "<!--MINER_ROW-->", s) totfees += srt[i].fees } mnrs = strings.Replace(mnrs, "<!--TOTAL_MINING_FEES-->", btc.UintToBtc(totfees), 1) mnrs = strings.Replace(mnrs, "<!--AVERAGE_FEE_PER_BYTE-->", fmt.Sprint(totfees/totbts), 1) var bv string for k, v := range block_versions { if bv != "" { bv += " + " } bv += fmt.Sprintf("%dx%d", v, k) } mnrs = strings.Replace(mnrs, "<!--BLOCK_VERSIONS-->", bv, 1) // bip100 bv = "" for k, v := range bip100_voting { if bv != "" { bv += " + " } bv += fmt.Sprintf("%sx%d", k, v) } mnrs = strings.Replace(mnrs, "<!--BLOCKSIZE_VOTES-->", bv, 1) write_html_head(w, r) w.Write([]byte(mnrs)) write_html_tail(w) }
func p_blocks(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } blks := load_template("blocks.html") onerow := load_template("blocks_row.html") common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() for cnt := uint32(0); end != nil && cnt < atomic.LoadUint32(&common.CFG.WebUI.ShowBlocks); cnt++ { bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return } block, e := btc.NewBlock(bl) if e != nil { return } cbasetx, _ := btc.NewTx(bl[block.TxOffset:]) s := onerow s = strings.Replace(s, "{BLOCK_NUMBER}", fmt.Sprint(end.Height), 1) s = strings.Replace(s, "{BLOCK_TIMESTAMP}", time.Unix(int64(block.BlockTime()), 0).Format("Mon 15:04:05"), 1) s = strings.Replace(s, "{BLOCK_HASH}", end.BlockHash.String(), 1) s = strings.Replace(s, "{BLOCK_TXS}", fmt.Sprint(block.TxCount), 1) s = strings.Replace(s, "{BLOCK_SIZE}", fmt.Sprintf("%.1f", float64(len(bl))/1000), 1) var rew uint64 for o := range cbasetx.TxOut { rew += cbasetx.TxOut[o].Value } s = strings.Replace(s, "<!--BLOCK_VERSION-->", fmt.Sprint(block.Version()), 1) s = strings.Replace(s, "{BLOCK_REWARD}", fmt.Sprintf("%.2f", float64(rew)/1e8), 1) mi, _ := common.TxMiner(cbasetx) if len(mi) > 10 { mi = mi[:10] } s = strings.Replace(s, "{BLOCK_MINER}", mi, 1) network.MutexRcv.Lock() rb := network.ReceivedBlocks[end.BlockHash.BIdx()] network.MutexRcv.Unlock() if rb.TmDownload != 0 { s = strings.Replace(s, "{TIME_TO_DOWNLOAD}", fmt.Sprint(int(rb.TmDownload/time.Millisecond)), 1) } else { s = strings.Replace(s, "{TIME_TO_DOWNLOAD}", "", 1) } if rb.TmAccept != 0 { s = strings.Replace(s, "{TIME_TO_ACCEPT}", fmt.Sprint(int(rb.TmAccept/time.Millisecond)), 1) } else { s = strings.Replace(s, "{TIME_TO_ACCEPT}", "", 1) } if rb.Cnt != 0 { s = strings.Replace(s, "{WASTED_BLOCKS}", fmt.Sprint(rb.Cnt), 1) } else { s = strings.Replace(s, "{WASTED_BLOCKS}", "", 1) } s = strings.Replace(s, "{TIME_RECEIVED}", rb.Time.Format("15:04:05"), 1) blks = templ_add(blks, "<!--BLOCK_ROW-->", s) end = end.Parent } write_html_head(w, r) w.Write([]byte(blks)) write_html_tail(w) }
func do_mining(s string) { var totbtc, hrs uint64 if s != "" { hrs, _ = strconv.ParseUint(s, 10, 64) } if hrs == 0 { hrs = uint64(common.CFG.MiningStatHours) } fmt.Println("Looking back", hrs, "hours...") lim := uint32(time.Now().Add(-time.Hour * time.Duration(hrs)).Unix()) common.Last.Mutex.Lock() bte := common.Last.Block end := bte common.Last.Mutex.Unlock() cnt, diff := 0, float64(0) tot_blocks, tot_blocks_len := 0, 0 bip100_voting := make(map[string]uint) bip100x := regexp.MustCompile("/BV{0,1}[0-9]+[M]{0,1}/") for end.Timestamp() >= lim { bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { println(cnt, e.Error()) return } block, e := btc.NewBlock(bl) if e != nil { println("btc.NewBlock failed", e.Error()) return } bt, _ := btc.NewBlock(bl) cbasetx, cbtxlen := btc.NewTx(bl[bt.TxOffset:]) tot_blocks++ tot_blocks_len += len(bl) diff += btc.GetDifficulty(block.Bits()) common.LockCfg() if common.CFG.Beeps.MinerID != "" && bytes.Contains(bl[bt.TxOffset:bt.TxOffset+cbtxlen], []byte(common.CFG.Beeps.MinerID)) { block.BuildTxList() totbtc += block.Txs[0].TxOut[0].Value cnt++ fmt.Printf("%4d) %6d %s %s %5.2f => %5.2f BTC total, %d txs, %.1f KB\n", cnt, end.Height, end.BlockHash.String(), time.Unix(int64(end.Timestamp()), 0).Format("2006-01-02 15:04:05"), float64(block.Txs[0].TxOut[0].Value)/1e8, float64(totbtc)/1e8, len(block.Txs), float64(len(bl))/1e3) } common.UnlockCfg() res := bip100x.Find(cbasetx.TxIn[0].ScriptSig) if res != nil { bip100_voting[string(res)]++ nimer, _ := common.TxMiner(cbasetx) fmt.Println(" block", end.Height, "by", nimer, "voting", string(res), " total:", bip100_voting[string(res)]) } end = end.Parent } if tot_blocks == 0 { fmt.Println("There are no blocks from the last", hrs, "hour(s)") return } diff /= float64(tot_blocks) common.LockCfg() if common.CFG.Beeps.MinerID != "" { fmt.Printf("%.8f BTC mined by %s, in %d blocks for the last %d hours\n", float64(totbtc)/1e8, common.CFG.Beeps.MinerID, cnt, hrs) } common.UnlockCfg() if cnt > 0 { fmt.Printf("Projected weekly income : %.0f BTC, estimated hashrate : %s\n", 7*24*float64(totbtc)/float64(hrs)/1e8, common.HashrateToString(float64(cnt)/float64(6*hrs)*diff*7158278.826667)) } bph := float64(tot_blocks) / float64(hrs) fmt.Printf("Total network hashrate : %s @ average diff %.0f (%.2f bph)\n", common.HashrateToString(bph/6*diff*7158278.826667), diff, bph) fmt.Printf("Average block size was %.1f KB, next difficulty change in %d blocks\n", float64(tot_blocks_len/tot_blocks)/1e3, 2016-bte.Height%2016) }