func (c *OneConnection) HandleAlert(b []byte) { var rh [20]byte btc.RimpHash(b, rh[:]) alidx := binary.LittleEndian.Uint64(rh[0:8]) Alert_access.Lock() // protect access to the map while in the function defer Alert_access.Unlock() if _, ok := Alerts[alidx]; ok { return // already have this one } a, e := btc.NewAlert(b, AlertPubKey) if e != nil { println(c.PeerAddr.String(), "- sent us a broken alert:", e.Error()) if a == nil { //println("With apparently broken signature - so ban it!") c.DoS("BrokenAlert") } else { println(hex.EncodeToString(b)) } return } Alerts[alidx] = a NetAlerts <- a.StatusBar return }
// It is assumed that you call this function only after rec.IsStealthIdx() was true func CheckStealthRec(db *qdb.DB, k qdb.KeyType, rec *chain.OneWalkRecord, addr *btc.BtcAddr, d []byte, inbrowse bool) (fl uint32, uo *chain.OneUnspentTx) { sth_scr := rec.Script() sa := addr.StealthAddr if sa.CheckNonce(sth_scr[3:]) { vo := rec.VOut() // get the spending output var spend_v []byte if inbrowse { spend_v = db.GetNoMutex(qdb.KeyType(uint64(k) ^ uint64(vo) ^ uint64(vo+1))) } else { spend_v = db.Get(qdb.KeyType(uint64(k) ^ uint64(vo) ^ uint64(vo+1))) } if spend_v != nil { rec = chain.NewWalkRecord(spend_v) if rec.IsP2KH() { var h160 [20]byte c := btc.StealthDH(sth_scr[7:40], d) spen_exp := btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(rec.Script()[3:23], h160[:]) { adr := btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo = rec.ToUnspent(adr) adr.StealthAddr = sa adr.Extra = addr.Extra uo.StealthC = c } } else { fl = chain.WALK_NOMORE } } else { fl = chain.WALK_NOMORE } } return }
func list_unspent(addr string) { fmt.Println("Checking unspent coins for addr", addr) defer func() { // in case if ad.OutScript() would panic if r := recover(); r != nil { err := r.(error) fmt.Println("main panic recovered:", err.Error()) } }() var ad *btc.BtcAddr var e error ad, e = btc.NewAddrFromString(addr) if e != nil { println(e.Error()) return } sa := ad.StealthAddr var walk chain.FunctionWalkUnspent var unsp chain.AllUnspentTx if sa == nil { exp_scr := ad.OutScript() walk = func(tx *chain.QdbRec) { for idx, rec := range tx.Outs { if rec != nil && bytes.Equal(rec.PKScr, exp_scr) { unsp = append(unsp, tx.ToUnspent(uint32(idx), ad)) } } } } else { var c, spen_exp []byte var rec, out *chain.QdbTxOut var h160 [20]byte wallet.FetchStealthKeys() d := wallet.FindStealthSecret(sa) if d == nil { fmt.Println("No matching secret found in your wallet/stealth folder") return } walk = func(tx *chain.QdbRec) { for i := 0; i < len(tx.Outs)-1; i++ { if rec = tx.Outs[i]; rec == nil { continue } if out = tx.Outs[i+1]; out == nil { continue } if !rec.IsStealthIdx() || !out.IsP2KH() || !ad.StealthAddr.CheckNonce(rec.PKScr[3:40]) { continue } c = btc.StealthDH(rec.PKScr[7:40], d) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(i + 1) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.Extra uo.StealthC = c unsp = append(unsp, uo) } } } } common.BlockChain.Unspent.BrowseUTXO(false, walk) sort.Sort(unsp) var sum uint64 for i := range unsp { if len(unsp) < 200 { fmt.Println(unsp[i].String()) } sum += unsp[i].Value } fmt.Printf("Total %.8f unspent BTC in %d outputs at address %s\n", float64(sum)/1e8, len(unsp), ad.String()) }
func do_scan_stealth(p string, ignore_prefix bool) { ad, _ := btc.NewAddrFromString(p) if ad == nil { fmt.Println("Specify base58 encoded bitcoin address") return } sa := ad.StealthAddr if sa == nil { fmt.Println("Specify base58 encoded stealth address") return } if sa.Version != btc.StealthAddressVersion(common.Testnet) { fmt.Println("Incorrect version of the stealth address") return } if len(sa.SpendKeys) != 1 { fmt.Println("Currently only single spend keys are supported. This address has", len(sa.SpendKeys)) return } //fmt.Println("scankey", hex.EncodeToString(sa.ScanKey[:])) if ignore_prefix { sa.Prefix = []byte{0} fmt.Println("Ignoring Prefix inside the address") } else if len(sa.Prefix) == 0 { fmt.Println("Prefix not present in the address") } else { fmt.Println("Prefix", sa.Prefix[0], hex.EncodeToString(sa.Prefix[1:])) } wallet.FetchStealthKeys() d := wallet.FindStealthSecret(sa) if d == nil { fmt.Println("No matching secret found in your wallet/stealth folder") return } var unsp chain.AllUnspentTx var c, spen_exp []byte var rec, out *chain.QdbTxOut var h160 [20]byte common.BlockChain.Unspent.BrowseUTXO(true, func(tx *chain.QdbRec) { for i := 0; i < len(tx.Outs)-1; i++ { if rec = tx.Outs[i]; rec == nil { continue } if out = tx.Outs[i+1]; out == nil { continue } if !rec.IsStealthIdx() || !out.IsP2KH() || !ad.StealthAddr.CheckNonce(rec.PKScr[3:40]) { continue } c = btc.StealthDH(rec.PKScr[7:40], d) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(i + 1) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.Extra uo.StealthC = c unsp = append(unsp, uo) } } }) sort.Sort(unsp) os.RemoveAll("balance") os.MkdirAll("balance/", 0770) utxt, _ := os.Create("balance/unspent.txt") fmt.Print(wallet.DumpBalance(unsp, utxt, true, false)) }
// This function is only used when loading UTXO database func newUTXO(tx *chain.QdbRec) (update_wallet bool) { var c, spen_exp []byte var rec *chain.QdbTxOut var h160 [20]byte check_next_address: for idx, out := range tx.Outs { if out == nil { continue } // check for stealth if len(StealthAdCache) > 0 && idx > 0 { if rec = tx.Outs[idx-1]; rec == nil { goto not_stealth } if !rec.IsStealthIdx() || !out.IsP2KH() { goto not_stealth } for _, ad := range StealthAdCache { if sa := ad.addr.StealthAddr; sa.CheckNonce(rec.PKScr[3:40]) { c = btc.StealthDH(rec.PKScr[7:40], ad.d[:]) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(idx) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.addr.Extra uo.StealthC = c carec := CachedAddrs[ad.h160] carec.Value += uo.Value CacheUnspent[carec.CacheIndex].AllUnspentTx = append(CacheUnspent[carec.CacheIndex].AllUnspentTx, uo) CacheUnspentIdx[uo.TxPrevOut.UIdx()] = &OneCachedUnspentIdx{Index: carec.CacheIndex, Record: uo} if carec.InWallet { update_wallet = true } continue check_next_address // it it was setalth, cannot be enythign else } } } } not_stealth: // Extract hash160 from pkscript adr := btc.NewAddrFromPkScript(out.PKScr, common.Testnet) if adr != nil { if carec, ok := CachedAddrs[adr.Hash160]; ok { carec.Value += out.Value utxo := new(chain.OneUnspentTx) utxo.TxPrevOut.Hash = tx.TxID utxo.TxPrevOut.Vout = uint32(idx) utxo.Value = out.Value utxo.MinedAt = tx.InBlock utxo.BtcAddr = CacheUnspent[carec.CacheIndex].BtcAddr CacheUnspent[carec.CacheIndex].AllUnspentTx = append(CacheUnspent[carec.CacheIndex].AllUnspentTx, utxo) CacheUnspentIdx[utxo.TxPrevOut.UIdx()] = &OneCachedUnspentIdx{Index: carec.CacheIndex, Record: utxo} if carec.InWallet { update_wallet = true } } } } return }
func update_balance() { var tofetch_stealh []*btc.BtcAddr var tofetch_secrets [][]byte tofetch_regular := make(map[uint64]*btc.BtcAddr) MyBalance = nil for _, v := range CachedAddrs { v.InWallet = false } FetchStealthKeys() for i := range MyWallet.Addrs { if rec, pres := CachedAddrs[MyWallet.Addrs[i].Hash160]; pres { rec.InWallet = true cu := CacheUnspent[rec.CacheIndex] cu.BtcAddr = MyWallet.Addrs[i] for j := range cu.AllUnspentTx { // update BtcAddr in each of AllUnspentTx to reflect the latest label cu.AllUnspentTx[j].BtcAddr = MyWallet.Addrs[i] } MyBalance = append(MyBalance, CacheUnspent[rec.CacheIndex].AllUnspentTx...) } else { add_it := true // Add a new address to the balance cache if MyWallet.Addrs[i].StealthAddr == nil { tofetch_regular[MyWallet.Addrs[i].AIdx()] = MyWallet.Addrs[i] } else { sa := MyWallet.Addrs[i].StealthAddr if ssecret := FindStealthSecret(sa); ssecret != nil { tofetch_stealh = append(tofetch_stealh, MyWallet.Addrs[i]) tofetch_secrets = append(tofetch_secrets, ssecret) var rec stealthCacheRec rec.addr = MyWallet.Addrs[i] copy(rec.d[:], ssecret) copy(rec.h160[:], MyWallet.Addrs[i].Hash160[:]) StealthAdCache = append(StealthAdCache, rec) } else { if MyWallet.Addrs[i].Extra.Wallet != AddrBookFileName { fmt.Println("No matching secret for", sa.String()) } add_it = false } } if add_it { CachedAddrs[MyWallet.Addrs[i].Hash160] = &OneCachedAddrBalance{InWallet: true, CacheIndex: uint(len(CacheUnspent))} CacheUnspent = append(CacheUnspent, &OneCachedUnspent{BtcAddr: MyWallet.Addrs[i]}) } } } if len(tofetch_regular) > 0 || len(tofetch_stealh) > 0 { fmt.Println("Fetching a new blance for", len(tofetch_regular), "regular and", len(tofetch_stealh), "stealth addresses") // There are new addresses which we have not monitored yet var new_addrs chain.AllUnspentTx var c, spen_exp []byte var out *chain.QdbTxOut var h160 [20]byte common.BlockChain.Unspent.BrowseUTXO(true, func(tx *chain.QdbRec) { for idx, rec := range tx.Outs { if rec == nil { continue } if rec.IsP2KH() { if ad, ok := tofetch_regular[binary.LittleEndian.Uint64(rec.PKScr[3:3+8])]; ok { new_addrs = append(new_addrs, tx.ToUnspent(uint32(idx), ad)) } } else if rec.IsP2SH() { if ad, ok := tofetch_regular[binary.LittleEndian.Uint64(rec.PKScr[2:2+8])]; ok { new_addrs = append(new_addrs, tx.ToUnspent(uint32(idx), ad)) } } else if idx < len(tx.Outs)-1 { // check for stealth if out = tx.Outs[idx+1]; out == nil { continue } if !rec.IsStealthIdx() || !out.IsP2KH() { continue } stealth_check: for _, ad := range tofetch_stealh { if sa := ad.StealthAddr; sa.CheckNonce(rec.PKScr[3:40]) { for _, d := range tofetch_secrets { c = btc.StealthDH(rec.PKScr[7:40], d) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(idx + 1) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.Extra uo.StealthC = c new_addrs = append(new_addrs, uo) break stealth_check } } } } } } }) for i := range new_addrs { poi := new_addrs[i].TxPrevOut.UIdx() if _, ok := CacheUnspentIdx[poi]; ok { fmt.Println(new_addrs[i].TxPrevOut.String(), "- already on the list") continue } var rec *OneCachedAddrBalance if new_addrs[i].BtcAddr.StealthAddr != nil { var h160 [20]byte copy(h160[:], new_addrs[i].BtcAddr.StealthAddr.Hash160()) rec = CachedAddrs[h160] } else { rec = CachedAddrs[new_addrs[i].BtcAddr.Hash160] } if rec == nil { println("Hash160 not in CachedAddrs for", new_addrs[i].BtcAddr.String()) continue } rec.Value += new_addrs[i].Value CacheUnspent[rec.CacheIndex].AllUnspentTx = append(CacheUnspent[rec.CacheIndex].AllUnspentTx, new_addrs[i]) CacheUnspentIdx[new_addrs[i].TxPrevOut.UIdx()] = &OneCachedUnspentIdx{Index: rec.CacheIndex, Record: new_addrs[i]} } MyBalance = append(MyBalance, new_addrs...) } sort_and_sum() }
// Get the secret seed and generate "keycnt" key pairs (both private and public) func make_wallet() { var lab string load_others() var seed_key []byte var hdwal *btc.HDWallet defer func() { sys.ClearBuffer(seed_key) if hdwal != nil { sys.ClearBuffer(hdwal.Key) sys.ClearBuffer(hdwal.ChCode) } }() pass := getpass() if pass == nil { cleanExit(0) } if waltype >= 1 && waltype <= 3 { seed_key = make([]byte, 32) btc.ShaHash(pass, seed_key) sys.ClearBuffer(pass) lab = fmt.Sprintf("Typ%c", 'A'+waltype-1) if waltype == 1 { println("WARNING: Wallet Type 1 is obsolete") } else if waltype == 2 { if type2sec != "" { d, e := hex.DecodeString(type2sec) if e != nil { println("t2sec error:", e.Error()) cleanExit(1) } type2_secret = d } else { type2_secret = make([]byte, 20) btc.RimpHash(seed_key, type2_secret) } } } else if waltype == 4 { lab = "TypHD" hdwal = btc.MasterKey(pass, testnet) sys.ClearBuffer(pass) } else { sys.ClearBuffer(pass) println("ERROR: Unsupported wallet type", waltype) cleanExit(1) } if *verbose { fmt.Println("Generating", keycnt, "keys, version", ver_pubkey(), "...") } first_determ_idx = len(keys) for i := uint(0); i < keycnt; { prv_key := make([]byte, 32) if waltype == 3 { btc.ShaHash(seed_key, prv_key) seed_key = append(seed_key, byte(i)) } else if waltype == 2 { seed_key = btc.DeriveNextPrivate(seed_key, type2_secret) copy(prv_key, seed_key) } else if waltype == 1 { btc.ShaHash(seed_key, prv_key) copy(seed_key, prv_key) } else /*if waltype==4*/ { // HD wallet _hd := hdwal.Child(uint32(0x80000000 | i)) copy(prv_key, _hd.Key[1:]) sys.ClearBuffer(_hd.Key) sys.ClearBuffer(_hd.ChCode) } if *scankey != "" { new_stealth_address(prv_key) return } rec := btc.NewPrivateAddr(prv_key, ver_secret(), !uncompressed) if *pubkey != "" && *pubkey == rec.BtcAddr.String() { fmt.Println("Public address:", rec.BtcAddr.String()) fmt.Println("Public hexdump:", hex.EncodeToString(rec.BtcAddr.Pubkey)) return } rec.BtcAddr.Extra.Label = fmt.Sprint(lab, " ", i+1) keys = append(keys, rec) i++ } if *verbose { fmt.Println("Private keys re-generated") } // Calculate SegWit addresses segwit = make([]*btc.BtcAddr, len(keys)) for i, pk := range keys { if len(pk.Pubkey) != 33 { continue } h160 := btc.Rimp160AfterSha256(append([]byte{0, 20}, pk.Hash160[:]...)) segwit[i] = btc.NewAddrFromHash160(h160[:], btc.AddrVerScript(testnet)) } }
// Get the secret seed and generate "keycnt" key pairs (both private and public) func make_wallet() { var lab string load_others() seed_key := make([]byte, 32) if !getseed(seed_key) { os.Exit(0) } defer func() { sys.ClearBuffer(seed_key) }() switch waltype { case 1: lab = "TypA" println("WARNING: Wallet Type 1 is obsolete") case 2: lab = "TypB" if type2sec != "" { d, e := hex.DecodeString(type2sec) if e != nil { println("t2sec error:", e.Error()) os.Exit(1) } type2_secret = d } else { type2_secret = make([]byte, 20) btc.RimpHash(seed_key, type2_secret) } case 3: lab = "TypC" default: println("ERROR: Unsupported wallet type", waltype) os.Exit(0) } if *verbose { fmt.Println("Generating", keycnt, "keys, version", AddrVerPubkey(), "...") } for i := uint(0); i < keycnt; { prv_key := make([]byte, 32) if waltype == 3 { btc.ShaHash(seed_key, prv_key) seed_key = append(seed_key, byte(i)) } else if waltype == 2 { seed_key = btc.DeriveNextPrivate(seed_key, type2_secret) copy(prv_key, seed_key) } else { btc.ShaHash(seed_key, prv_key) copy(seed_key, prv_key) } priv_keys = append(priv_keys, prv_key) if *scankey != "" { new_stealth_address(prv_key) return } // for stealth keys if i == 0 { copy(first_seed[:], prv_key) } compressed_key = append(compressed_key, !uncompressed) pub := btc.PublicFromPrivate(prv_key, !uncompressed) if pub != nil { adr := btc.NewAddrFromPubkey(pub, AddrVerPubkey()) if *pubkey != "" && *pubkey == adr.String() { fmt.Println("Public address:", adr.String()) fmt.Println("Public hexdump:", hex.EncodeToString(pub)) return } publ_addrs = append(publ_addrs, adr) labels = append(labels, fmt.Sprint(lab, " ", i+1)) i++ } else { println("PublicFromPrivate error 3") } } if *verbose { fmt.Println("Private keys re-generated") } }