github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/tools/unspent4_to_UTXO/unspent4_to_UTXO.go (about) 1 package main 2 3 import ( 4 "strings" 5 "strconv" 6 "bufio" 7 "encoding/binary" 8 "fmt" 9 "github.com/piotrnar/gocoin/lib/btc" 10 "github.com/piotrnar/gocoin/lib/others/qdb" 11 "io/ioutil" 12 "os" 13 "time" 14 ) 15 16 var ( 17 block_height uint64 18 block_hash []byte 19 ) 20 21 func load_map4() (ndb map[qdb.KeyType][]byte) { 22 var odb *qdb.DB 23 ndb = make(map[qdb.KeyType][]byte, 21e6) 24 for i := 0; i < 16; i++ { 25 fmt.Print("\r", i, " of 16 ... ") 26 er := qdb.NewDBExt(&odb, &qdb.NewDBOpts{Dir: fmt.Sprintf("unspent4/%06d", i), 27 Volatile: true, LoadData: true, WalkFunction: func(key qdb.KeyType, val []byte) uint32 { 28 if _, ok := ndb[key]; ok { 29 panic("duplicate") 30 } 31 ndb[key] = val 32 return 0 33 }}) 34 if er != nil { 35 fmt.Println(er.Error()) 36 return 37 } 38 odb.Close() 39 } 40 fmt.Print("\r \r") 41 return 42 } 43 44 45 func load_last_block() { 46 var maxbl_fn string 47 48 fis, _ := ioutil.ReadDir("unspent4/") 49 var maxbl, undobl int 50 for _, fi := range fis { 51 if !fi.IsDir() && fi.Size() >= 32 { 52 ss := strings.SplitN(fi.Name(), ".", 2) 53 cb, er := strconv.ParseUint(ss[0], 10, 32) 54 if er == nil && int(cb) > maxbl { 55 maxbl = int(cb) 56 maxbl_fn = fi.Name() 57 if len(ss) == 2 && ss[1] == "tmp" { 58 undobl = maxbl 59 } 60 } 61 } 62 } 63 if maxbl == 0 { 64 fmt.Println("This unspent4 database is corrupt") 65 return 66 } 67 if undobl == maxbl { 68 fmt.Println("This unspent4 database is not properly closed") 69 return 70 } 71 72 block_height = uint64(maxbl) 73 block_hash = make([]byte, 32) 74 75 f, _ := os.Open("unspent4/"+maxbl_fn) 76 f.Read(block_hash) 77 f.Close() 78 79 } 80 81 func save_map(ndb map[qdb.KeyType][]byte) { 82 var cnt_dwn, cnt_dwn_from, perc int 83 of, er := os.Create("UTXO.db") 84 if er != nil { 85 fmt.Println("Create file:", er.Error()) 86 return 87 } 88 89 cnt_dwn_from = len(ndb) / 100 90 wr := bufio.NewWriter(of) 91 binary.Write(wr, binary.LittleEndian, uint64(block_height)) 92 wr.Write(block_hash) 93 binary.Write(wr, binary.LittleEndian, uint64(len(ndb))) 94 for k, v := range ndb { 95 btc.WriteVlen(wr, uint64(len(v)+8)) 96 binary.Write(wr, binary.LittleEndian, k) 97 //binary.Write(wr, binary.LittleEndian, uint32(len(v))) 98 _, er = wr.Write(v) 99 if er != nil { 100 fmt.Println("\n\007Fatal error:", er.Error()) 101 break 102 } 103 if cnt_dwn == 0 { 104 fmt.Print("\rSaving UTXO.db - ", perc, "% complete ... ") 105 cnt_dwn = cnt_dwn_from 106 perc++ 107 } else { 108 cnt_dwn-- 109 } 110 } 111 wr.Flush() 112 of.Close() 113 114 fmt.Print("\r \r") 115 } 116 117 func main() { 118 var sta time.Time 119 120 if fi, er := os.Stat("unspent4"); er!=nil || !fi.IsDir() { 121 fmt.Println("ERROR: Input database not found.") 122 fmt.Println("Make sure to have unspent4/ directory, where you run this tool from") 123 return 124 } 125 126 load_last_block() 127 if len(block_hash)!=32 { 128 fmt.Println("ERROR: Could not recover last block's data from the input database", len(block_hash)) 129 return 130 } 131 132 fmt.Println("Loading input database. Block", block_height, btc.NewUint256(block_hash).String()) 133 sta = time.Now() 134 ndb := load_map4() 135 fmt.Println(len(ndb), "records loaded in", time.Now().Sub(sta).String()) 136 137 sta = time.Now() 138 save_map(ndb) 139 fmt.Println("Saved in in", time.Now().Sub(sta).String()) 140 }