github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/usif/textui/utxo.go (about)

     1  package textui
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"sort"
     7  
     8  	"github.com/piotrnar/gocoin/client/common"
     9  	"github.com/piotrnar/gocoin/lib/utxo"
    10  )
    11  
    12  // inspired by https://bitcoinmagazine.com/technical/utxoracle-model-could-bring-use-cases-to-bitcoin
    13  func wallet_usd(s string) {
    14  	const MIN_BTC_VALUE = 20e3 // 0.001 BTC (not included)
    15  	const MAX_BTC_VALUE = 1e6  // 0.01 BTC (not included)
    16  	const VALUE_MULTIPLIER = 1000.0
    17  	const TICK_SPAN = 2
    18  
    19  	var blocks_back int
    20  	var most_often_sent_usd_amount float64
    21  	blocks_back = 144
    22  	most_often_sent_usd_amount = 50.0
    23  	fmt.Sscanf(s, "%d %f", &blocks_back, &most_often_sent_usd_amount)
    24  
    25  	if blocks_back < 1 {
    26  		println("Only positiove block values are allowed")
    27  		return
    28  	}
    29  	if most_often_sent_usd_amount < 10 || most_often_sent_usd_amount > 2000 {
    30  		println("Use USD amount between 10 and 2000")
    31  		return
    32  	}
    33  
    34  	db := common.BlockChain.Unspent
    35  
    36  	min_index := int64(VALUE_MULTIPLIER * (math.Log10(MIN_BTC_VALUE)))
    37  	max_index := int64(VALUE_MULTIPLIER * (math.Log10(MAX_BTC_VALUE)))
    38  
    39  	fmt.Printf("Checking UTXO from the last %d blocks, assuming the most common amount was %.2f USD\n", blocks_back, most_often_sent_usd_amount)
    40  
    41  	var rec *utxo.UtxoRec
    42  	from_block := db.LastBlockHeight - uint32(blocks_back)
    43  	occ := make([]int64, max_index-min_index)
    44  	for i := range db.HashMap {
    45  		for k, v := range db.HashMap[i] {
    46  			rec = utxo.NewUtxoRecStatic(k, v)
    47  			if rec.InBlock < from_block {
    48  				continue
    49  			}
    50  			for _, o := range rec.Outs {
    51  				if o != nil && o.Value > MIN_BTC_VALUE && o.Value < MAX_BTC_VALUE {
    52  					v10 := int64(VALUE_MULTIPLIER * (math.Log10(float64(o.Value))))
    53  					occ[v10-min_index]++
    54  				}
    55  			}
    56  		}
    57  	}
    58  
    59  	srtd := make([][2]int, len(occ)-2)
    60  	var ccc int
    61  	for i := TICK_SPAN; i < len(occ)-TICK_SPAN; i++ {
    62  		val := occ[i]
    63  		for ts := 1; ts <= TICK_SPAN; ts++ {
    64  			val += occ[i-ts] >> ts
    65  			val += occ[i+ts] >> ts
    66  		}
    67  		srtd[ccc][0] = i
    68  		srtd[ccc][1] = int(val)
    69  		ccc++
    70  	}
    71  	sort.Slice(srtd, func(i, j int) bool { return srtd[i][1] > srtd[j][1] })
    72  	fmt.Println("Most commonly used amounts:")
    73  	for i := range srtd[:10] {
    74  		hhi := srtd[i][0] + int(min_index)
    75  		hhval := srtd[i][1]
    76  		xxx := math.Pow(10, float64(hhi)/VALUE_MULTIPLIER)
    77  		fmt.Printf("Found high count (%d) at %d (%d sats). Estimated BTC price: %d USD\n",
    78  			hhval, hhi, int(xxx), int(most_often_sent_usd_amount*1e8/xxx))
    79  	}
    80  
    81  }
    82  
    83  func init() {
    84  	newUi("usd", true, wallet_usd, "Try to figure out recent BTC/USD price [block_count [most_common_usd]]")
    85  }