// LTC signing uses different seed string func HashFromMessage(msg []byte, out []byte) { const MessageMagic = "Litecoin Signed Message:\n" b := new(bytes.Buffer) btc.WriteVlen(b, uint64(len(MessageMagic))) b.Write([]byte(MessageMagic)) btc.WriteVlen(b, uint64(len(msg))) b.Write(msg) btc.ShaHash(b.Bytes(), out) }
func main() { if len(os.Args) != 5 { fmt.Println("This tool needs to be executed with 4 arguments:") fmt.Println(" 1) Name of the unsigned transaction file") fmt.Println(" 2) Input index to add the key & signature to") fmt.Println(" 3) Hex dump of the canonical signature") fmt.Println(" 4) Hex dump of the public key") return } tx := raw_tx_from_file(os.Args[1]) if tx == nil { return } in, er := strconv.ParseUint(os.Args[2], 10, 32) if er != nil { println("Input index:", er.Error()) return } if int(in) >= len(tx.TxIn) { println("Input index too big:", int(in), "/", len(tx.TxIn)) return } sig, er := hex.DecodeString(os.Args[3]) if er != nil { println("Signature:", er.Error()) return } pk, er := hex.DecodeString(os.Args[4]) if er != nil { println("Public key:", er.Error()) return } buf := new(bytes.Buffer) btc.WriteVlen(buf, uint64(len(sig))) buf.Write(sig) btc.WriteVlen(buf, uint64(len(pk))) buf.Write(pk) tx.TxIn[in].ScriptSig = buf.Bytes() write_tx_file(tx) }
func (c *OneConnection) SendOwnAddr() { if ExternalAddrLen() > 0 { buf := new(bytes.Buffer) btc.WriteVlen(buf, uint64(1)) binary.Write(buf, binary.LittleEndian, uint32(time.Now().Unix())) buf.Write(BestExternalAddr()) c.SendRawMsg("addr", buf.Bytes()) } }
func (c *OneConnection) SendAddr() { pers := peersdb.GetBestPeers(MaxAddrsPerMessage, nil) if len(pers) > 0 { buf := new(bytes.Buffer) btc.WriteVlen(buf, uint64(len(pers))) for i := range pers { binary.Write(buf, binary.LittleEndian, pers[i].Time) buf.Write(pers[i].NetAddr.Bytes()) } c.SendRawMsg("addr", buf.Bytes()) } }
func (c *OneConnection) SendInvs() (res bool) { b := new(bytes.Buffer) c.Mutex.Lock() if len(c.PendingInvs) > 0 { btc.WriteVlen(b, uint64(len(c.PendingInvs))) for i := range c.PendingInvs { b.Write((*c.PendingInvs[i])[:]) } res = true } c.PendingInvs = nil c.Mutex.Unlock() if res { c.SendRawMsg("inv", b.Bytes()) } return }
func (c *OneConnection) GetBlocks(pl []byte) { h2get, hashstop, e := parseLocatorsPayload(pl) if e != nil || len(h2get) < 1 || hashstop == nil { println("GetBlocks: error parsing payload from", c.PeerAddr.Ip()) c.DoS("BadGetBlks") return } invs := make(map[[32]byte]bool, 500) for i := range h2get { common.BlockChain.BlockIndexAccess.Lock() if bl, ok := common.BlockChain.BlockIndex[h2get[i].BIdx()]; ok { // make sure that this block is in our main chain common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() for ; end != nil && end.Height >= bl.Height; end = end.Parent { if end == bl { addInvBlockBranch(invs, bl, hashstop) // Yes - this is the main chain if common.DebugLevel > 0 { fmt.Println(c.PeerAddr.Ip(), "getblocks from", bl.Height, "stop at", hashstop.String(), "->", len(invs), "invs") } if len(invs) > 0 { common.BlockChain.BlockIndexAccess.Unlock() inv := new(bytes.Buffer) btc.WriteVlen(inv, uint64(len(invs))) for k, _ := range invs { binary.Write(inv, binary.LittleEndian, uint32(2)) inv.Write(k[:]) } c.SendRawMsg("inv", inv.Bytes()) return } } } } common.BlockChain.BlockIndexAccess.Unlock() } common.CountSafe("GetblksMissed") return }
// Handle getheaders protocol command // https://en.bitcoin.it/wiki/Protocol_specification#getheaders func (c *OneConnection) GetHeaders(pl []byte) { h2get, hashstop, e := parseLocatorsPayload(pl) if e != nil || hashstop == nil { println("GetHeaders: error parsing payload from", c.PeerAddr.Ip()) c.DoS("BadGetHdrs") return } if common.DebugLevel > 1 { println("GetHeaders", len(h2get), hashstop.String()) } var best_block, last_block *chain.BlockTreeNode common.BlockChain.BlockIndexAccess.Lock() if len(h2get) > 0 { for i := range h2get { if bl, ok := common.BlockChain.BlockIndex[h2get[i].BIdx()]; ok { if best_block == nil || bl.Height > best_block.Height { best_block = bl } } } } else { best_block = common.BlockChain.BlockIndex[hashstop.BIdx()] } last_block = common.BlockChain.BlockTreeEnd common.BlockChain.BlockIndexAccess.Unlock() var resp []byte var cnt uint32 for cnt < 2000 { best_block = best_block.FindPathTo(last_block) if best_block == nil { break } resp = append(resp, append(best_block.BlockHeader[:], 0)...) // 81st byte is always zero cnt++ } out := new(bytes.Buffer) btc.WriteVlen(out, uint64(cnt)) out.Write(resp) c.SendRawMsg("headers", out.Bytes()) return }
func (c *OneConnection) ProcessInv(pl []byte) { if len(pl) < 37 { println(c.PeerAddr.Ip(), "inv payload too short", len(pl)) return } c.InvsRecieved++ cnt, of := btc.VLen(pl) if len(pl) != of+36*cnt { println("inv payload length mismatch", len(pl), of, cnt) } var blinv2ask []byte for i := 0; i < cnt; i++ { typ := binary.LittleEndian.Uint32(pl[of : of+4]) common.CountSafe(fmt.Sprint("InvGot", typ)) if typ == 2 { if blockWanted(pl[of+4 : of+36]) { blinv2ask = append(blinv2ask, pl[of+4:of+36]...) } } else if typ == 1 { if common.CFG.TXPool.Enabled { c.TxInvNotify(pl[of+4 : of+36]) } } of += 36 } if len(blinv2ask) > 0 { bu := new(bytes.Buffer) btc.WriteVlen(bu, uint64(len(blinv2ask)/32)) for i := 0; i < len(blinv2ask); i += 32 { bh := btc.NewUint256(blinv2ask[i : i+32]) c.Mutex.Lock() c.GetBlockInProgress[bh.BIdx()] = &oneBlockDl{hash: bh, start: time.Now()} c.Mutex.Unlock() binary.Write(bu, binary.LittleEndian, uint32(2)) bu.Write(bh.Hash[:]) } c.SendRawMsg("getdata", bu.Bytes()) } return }
// Commit the given add/del transactions to UTXO and Wnwind DBs func (db *UnspentDB) CommitBlockTxs(changes *BlockChanges, blhash []byte) (e error) { undo_fn := fmt.Sprint(db.dir, changes.Height) if changes.UndoData != nil || (changes.Height%UnwindBufferMaxHistory) == 0 { bu := new(bytes.Buffer) bu.Write(blhash) if changes.UndoData != nil { for _, xx := range changes.UndoData { bin := xx.Serialize(true) btc.WriteVlen(bu, uint64(len(bin))) bu.Write(bin) } } ioutil.WriteFile(db.dir+"tmp", bu.Bytes(), 0666) os.Rename(db.dir+"tmp", undo_fn+".tmp") } db.nosync() db.commit(changes) if changes.LastKnownHeight <= changes.Height { db.Sync() } os.Rename(undo_fn+".tmp", undo_fn) if db.LastBlockHash == nil { db.LastBlockHash = make([]byte, 32) } copy(db.LastBlockHash, blhash) db.LastBlockHeight = changes.Height if changes.Height > UnwindBufferMaxHistory { os.Remove(fmt.Sprint(db.dir, changes.Height-UnwindBufferMaxHistory)) } return }
func (c *one_net_conn) getnextblock() { if len(BlockQueue)*avg_block_size() > MEM_CACHE { COUNTER("GDFU") time.Sleep(100 * time.Millisecond) return } var cnt int b := new(bytes.Buffer) vl := new(bytes.Buffer) avs := avg_block_size() blks_to_get := uint32(MEM_CACHE / avs) max_cnt_to_get := (MAX_GET_FROM_PEER / avs) + 1 if max_cnt_to_get > MAX_BLOCKS_AT_ONCE { max_cnt_to_get = MAX_BLOCKS_AT_ONCE } BlocksMutex.Lock() FetchBlocksTo = BlocksComplete + blks_to_get if FetchBlocksTo > LastBlockHeight { FetchBlocksTo = LastBlockHeight } bl_stage := uint32(0) for curblk := BlocksComplete; cnt < max_cnt_to_get; curblk++ { if curblk > FetchBlocksTo { if bl_stage == MAX_SAME_BLOCKS_AT_ONCE { break } bl_stage++ curblk = BlocksComplete } if _, done := BlocksCached[curblk]; done { continue } bh, ok := BlocksToGet[curblk] if !ok { continue } cbip := BlocksInProgress[bh] if cbip == nil { // if not in progress then we always take it cbip = &one_bip{Height: curblk} cbip.Conns = make(map[uint32]bool, MaxNetworkConns) } else if cbip.Count != bl_stage || cbip.Conns[c.id] { continue } if LastBlockAsked < curblk { LastBlockAsked = curblk } cbip.Count = bl_stage + 1 cbip.Conns[c.id] = true c.inprogress++ BlocksInProgress[bh] = cbip b.Write([]byte{2, 0, 0, 0}) b.Write(bh[:]) cnt++ } BlocksMutex.Unlock() if cnt > 0 { btc.WriteVlen(vl, uint64(cnt)) c.sendmsg("getdata", append(vl.Bytes(), b.Bytes()...)) COUNTER("GDYE") } else { COUNTER("GDNO") time.Sleep(100 * time.Millisecond) } c.Lock() c.last_blk_rcvd = time.Now() c.Unlock() }
func (c *OneConnection) ProcessGetData(pl []byte) { var notfound []byte //println(c.PeerAddr.Ip(), "getdata") b := bytes.NewReader(pl) cnt, e := btc.ReadVLen(b) if e != nil { println("ProcessGetData:", e.Error(), c.PeerAddr.Ip()) return } for i := 0; i < int(cnt); i++ { var typ uint32 var h [36]byte n, _ := b.Read(h[:]) if n != 36 { println("ProcessGetData: pl too short", c.PeerAddr.Ip()) return } typ = binary.LittleEndian.Uint32(h[:4]) common.CountSafe(fmt.Sprint("GetdataType", typ)) if typ == 2 { uh := btc.NewUint256(h[4:]) bl, _, er := common.BlockChain.Blocks.BlockGet(uh) if er == nil { c.SendRawMsg("block", bl) } else { notfound = append(notfound, h[:]...) } } else if typ == 1 { // transaction uh := btc.NewUint256(h[4:]) TxMutex.Lock() if tx, ok := TransactionsToSend[uh.BIdx()]; ok && tx.Blocked == 0 { tx.SentCnt++ tx.Lastsent = time.Now() TxMutex.Unlock() c.SendRawMsg("tx", tx.Data) } else { TxMutex.Unlock() notfound = append(notfound, h[:]...) } } else { if common.DebugLevel > 0 { println("getdata for type", typ, "not supported yet") } if typ > 0 && typ <= 3 /*3 is a filtered block(we dont support it)*/ { notfound = append(notfound, h[:]...) } } } if len(notfound) > 0 { buf := new(bytes.Buffer) btc.WriteVlen(buf, uint64(len(notfound)/36)) buf.Write(notfound) c.SendRawMsg("notfound", buf.Bytes()) } }