github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/www/resources/gocoin.js (about) 1 const min_btc_addr_len = 27 // 1111111111111111111114oLvT2 2 const b58set = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" 3 4 var prvpos = null 5 6 7 function ajax() { 8 try { xmlHttp=new XMLHttpRequest(); } 9 catch (e) { 10 try { xmlHttp=new ActiveXObject("Msxml2.XMLHTTP"); } 11 catch (e) { 12 try { xmlHttp=new ActiveXObject("Microsoft.XMLHTTP"); } 13 catch (e) { alert("AJAX error!"); return null; } 14 } 15 } 16 return xmlHttp; 17 } 18 19 function xval(xml,tag) { 20 try { 21 return xml.getElementsByTagName(tag)[0].childNodes[0].nodeValue; 22 } catch (e) { 23 return null 24 } 25 } 26 27 function config(q) { 28 document.location = 'cfg?sid='+sid+'&'+q 29 } 30 31 function leftpad(v,c,n) { 32 v = v.toString() 33 while (v.length<n) v=c+v 34 return v 35 } 36 37 function rightpad(v,c,n) { 38 v = v.toString() 39 while (v.length<n) v=v+c 40 return v 41 } 42 43 function val2str_pad(val,pad) { 44 var i,neg 45 if (neg=(val<0)) val=-val 46 var frac = (val%1e8).toString() 47 while (frac.length<8) frac='0'+frac 48 if (pad) { 49 frac='.'+frac 50 } else { 51 for (i=8; i>0 && frac[i-1]=='0'; i--); 52 if (i!=8) { 53 if (i>0) frac='.'+frac.substr(0,i) 54 else frac='' 55 } else frac='.'+frac 56 } 57 var btcs = Math.floor(val/1e8) 58 btcs=btcs.toString()+frac 59 return neg?('-'+btcs):btcs 60 } 61 62 function val2str(val) { 63 return val2str_pad(val,false) 64 } 65 66 function val2int(str) { 67 var ss=str.split('.') 68 if (ss.length==1) { 69 return parseInt(ss[0])*1e8 70 } else if (ss.length==2) { 71 if (ss[1].length>8) return Number.NaN 72 while (ss[1].length<8) ss[1]+='0' 73 return parseInt(ss[0])*1e8 + parseInt(ss[1]) 74 } 75 return Number.NaN 76 } 77 78 function tim2str(tim, timeonly) { 79 var d = new Date(tim*1000) 80 //var timeonly=false 81 var res = '' 82 if (!timeonly) { 83 res += d.getFullYear() + "/" + leftpad(d.getMonth()+1, "0", 2) + "/" + leftpad(d.getDate(), "0", 2) + ' ' 84 } 85 res += leftpad(d.getHours(), "0", 2) + ":" + leftpad(d.getMinutes(), "0", 2) + ":" + leftpad(d.getSeconds(), "0", 2) 86 return res 87 } 88 89 function pushtx() { 90 var rawtx = prompt("Enter raw transaction data (hexdump)") 91 if (rawtx!=null) { 92 var form = document.createElement("form") 93 form.setAttribute("method", "post") 94 form.setAttribute("action", "txs") 95 var rtx = document.createElement("input") 96 rtx.setAttribute("type", "hidden") 97 rtx.setAttribute("name", "rawtx") 98 rtx.setAttribute("value", rawtx) 99 form.appendChild(rtx) 100 document.body.appendChild(form) 101 form.submit() 102 } 103 } 104 105 function savecfg() { 106 document.location='/cfg?savecfg&sid='+sid 107 } 108 109 function bignum(n) { 110 if (n<10e3) { 111 if ((n%1)===0) { 112 return n + ' ' 113 } 114 return n.toFixed(1) + " " 115 } 116 if (n<10e6) { 117 return (n/1e3).toFixed(1) + " K" 118 } 119 if (n<10e9) { 120 return (n/1e6).toFixed(1) + " M" 121 } 122 if (n<10e12) { 123 return (n/1e9).toFixed(1) + " G" 124 } 125 if (n<10e15) { 126 return (n/1e12).toFixed(1) + " T" 127 } 128 if (n<10e18) { 129 return (n/1e15).toFixed(1) + " P" 130 } 131 if (n<10e21) { 132 return (n/1e18).toFixed(1) + " E" 133 } 134 if (n<10e24) { 135 return (n/1e21).toFixed(1) + " Z" 136 } 137 return (n/1e24).toFixed(2) + " Y" 138 } 139 140 function int2ip(i) { 141 var a = (i>>24)&255 142 var b = (i>>16)&255 143 var c = (i>>8)&255 144 var d = i&255 145 return a+'.'+b+'.'+c+'.'+d 146 } 147 148 function hex2array(t) { 149 if ((t.length & 1)==1) { 150 return null 151 } 152 var pkb = new Uint8Array(t.length/2) 153 for (var i = 0; i < t.length; i += 2) { 154 var v = parseInt(t.substr(i, 2), 16) 155 if (isNaN(v)) return null 156 pkb[i/2] = v 157 } 158 return pkb 159 } 160 161 function valid_pubkey(s) { 162 if (s.length == 66 && (s.substr(0,2)=="02" || s.substr(0,2)=="03")) { 163 s = s.toLowerCase() 164 for (var i=0; i<s.length; i++) { 165 var c = s[i] 166 if (!(c >= '0' && c <= '9' || c >= 'a' && c <= 'f')) return false 167 } 168 return true 169 } 170 return false 171 } 172 173 function valid_bech32_addr(s) { 174 return (s.length == 62 || s.length==42) && (s.substr(0,3)=="bc1" || s.substr(0,3)=="tc1") 175 } 176 177 function valid_base58_addr(s) { 178 for (var i=0; i<s.length; s++) { 179 if (b58set.indexOf(s[i])==-1) { 180 return false 181 } 182 } 183 return true 184 } 185 186 function valid_btc_addr(s) { 187 try { 188 if (s.length<min_btc_addr_len) return false 189 if (s[0]=='#') return false 190 if (valid_pubkey(s)) return true 191 if (valid_bech32_addr(s)) return true 192 if (valid_base58_addr(s)) return true 193 } catch (e) { 194 console.log("valid_btc_addr:", e) 195 return false 196 } 197 } 198 199 function period2str(upsec) { 200 if (upsec<120) { 201 return upsec + ' sec' 202 } 203 var mins = upsec/60 204 if (mins<120) { 205 return mins.toFixed(1) + ' min' 206 } 207 208 var hrs = mins/60 209 if (hrs<48) { 210 return hrs.toFixed(1) + ' hours' 211 } 212 213 var days = hrs/24 214 return days.toFixed(1) + ' days' 215 } 216 217 function parse_wallet(s) { 218 var wallet = new Array() 219 try { 220 var cont = s.split('\n') 221 for (var i=0; i<cont.length; i++) { 222 var line = cont[i].trim() 223 var sp_idx = line.indexOf(' ') 224 var addr, label 225 if (sp_idx==-1) { 226 addr = line 227 label = '' 228 } else { 229 addr = line.substr(0, sp_idx) 230 label = line.substr(sp_idx+1) 231 } 232 if (valid_btc_addr(addr)) { 233 wallet.push({'addr':addr, 'label':label, 'virgin':cont[i][0]==' '}) 234 } 235 } 236 } catch (e) { 237 console.log("parse_wallet:", e) 238 } 239 return wallet 240 } 241 242 function build_wallet_list() { 243 var gvi = localStorage.getItem("gocoinWalletId") 244 var i 245 246 var names = localStorage.getItem("gocoinWallets").split('|') 247 var s = '' 248 for (i=0; i<names.length; i++) { 249 if (names[i]!="") { 250 var content = localStorage.getItem("gocoinWal_"+names[i]) 251 if (typeof(content)=="string" && content.length > 0) { 252 var o = document.createElement("option") 253 o.value = o.text = names[i] 254 qswal.add(o) 255 if (localStorage.getItem("gocoinWalletSelected")==names[i]) { 256 qswal.selectedIndex = qswal.length-1 257 } 258 if (s!='') s+='|' 259 s += names[i] 260 } else { 261 console.log("removing webwallet", names[i]) 262 localStorage.removeItem("gocoinWal_"+names[i]) 263 } 264 } 265 } 266 localStorage.setItem("gocoinWallets", s) 267 } 268 269 function quick_switch_wallet() { 270 try { 271 if (qswal.options.length==0 || qswal.selectedIndex<0 || qswal.options.length<=qswal.selectedIndex) return 272 var name = qswal.options[qswal.selectedIndex].text 273 localStorage.setItem("gocoinWalletSelected", name) 274 var e = document.createEvent("Event") 275 e.initEvent("loadwallet", false, false) 276 e.name = name 277 qswal.dispatchEvent(e) 278 } catch (e) { 279 console.log("quick_switch_wallet:", e) 280 } 281 } 282 283 function noscroll() { 284 scroll(0,0) 285 } 286 287 function closepopup_x(fees) { 288 if (light.style.display!='none') { 289 if (fees) { 290 $("#block_fees").unbind("plothover") 291 $("#fees_tooltip").remove() 292 } 293 light.style.display='none' 294 fade.style.display='none' 295 window.scrollTo(0,prvpos) 296 document.removeEventListener("scroll", noscroll) 297 } 298 } 299 300 function closepopup() { 301 closepopup_x(true) 302 } 303 304 function css(selector, property, value) { 305 for (var i=0; i<document.styleSheets.length;i++) {//Loop through all styles 306 //Try add rule 307 try { 308 document.styleSheets[i].insertRule(selector+ ' {'+property+':'+value+'}', document.styleSheets[i].cssRules.length); 309 } catch(err) {try { document.styleSheets[i].addRule(selector, property+':'+value);} catch(err) {}}//IE 310 } 311 } 312 313 314 var last_height // used for showing block fees 315 var fees_plot_data = [ { data : [] } ]; 316 var previousPoint = null 317 var max_spb, totbytes 318 319 function show_fees_tooltip(x, y, contents) { 320 $('<div id="fees_tooltip">' + contents + '</div>').css( { 321 'position': 'absolute', 322 'display': 'none', 323 'top': y - 29, 324 'left': x + 4, 325 'text-align' : 'center', 326 'z-index': 9999, 327 'border': '2px solid green', 328 'padding': '5px', 329 'font-size' : '12px', 330 'background-color': '#c0c0c0', 331 'opacity': 1 332 }).appendTo("body").fadeIn(200); 333 } 334 335 function show_cursor_tooltip(x, y, contents) { 336 $('<div id="fees_tooltip">' + contents + '</div>').css( { 337 'position': 'absolute', 338 'display': 'none', 339 'top': y - 29, 340 'left': x + 4, 341 'text-align' : 'center', 342 'border': '1px solid black', 343 'z-index': 9999, 344 'padding': '3px', 345 'font-size' : '12px', 346 'background-color': 'white', 347 'color': 'rgba(170, 0, 0, 0.80)', 348 'opacity': 1 349 }).appendTo("body").fadeIn(200); 350 } 351 352 function show_fees_handlehover(event, pos, item) { 353 if (item) { 354 if (previousPoint != item.dataIndex) { 355 var rec = fees_plot_data[0].data[item.dataIndex] 356 previousPoint = item.dataIndex 357 $("#fees_tooltip").remove() 358 var str = '<b>' + parseFloat(rec[1]).toFixed(2) + '</b> SPB at ' + 359 '<b>' + (100.0*rec[0]/1e6).toFixed(0) + '%</b><br>(of max block size)' 360 show_fees_tooltip(item.pageX, item.pageY, str) 361 } 362 } else { 363 $("#fees_tooltip").remove() 364 var x = pos.x 365 var y = pos.y 366 var show_x = (x >= 0 && x<=totbytes) 367 var show_y = (y >= 0 && y<=max_spb) 368 369 var str = '' 370 if (show_y) str += '<b>' + parseFloat(y).toFixed(2) + '</b> SPB' 371 if (show_x) { 372 if (str!='') str += ' | ' 373 str += '<b>' + (100.0*x/1e6).toFixed(0) + '%</b>' 374 } 375 if (str!='') { 376 show_cursor_tooltip(pos.pageX, pos.pageY, str) 377 } 378 379 previousPoint = null 380 } 381 } 382 383 function show_fees_clicked(height) { 384 var aj = ajax() 385 aj.onreadystatechange=function() { 386 if(aj.readyState==4) { 387 if (prvpos==null) { 388 fade.addEventListener('click', closepopup) 389 fade.style.cursor = 'pointer' 390 fade.title = 'Click here to close the popup' 391 } 392 393 prvpos = document.body.scrollTop 394 window.scrollTo(0,0) 395 396 light.style.display='block' 397 fade.style.display='block' 398 document.addEventListener("scroll", noscroll) 399 400 401 try { 402 var showblfees_stats = JSON.parse(aj.responseText) 403 404 // hide error message 405 stat_error.style.display = 'none' 406 407 if (block_fees_gru.checked) { 408 var stat2 = new Array() 409 var curr_elem = [0,0,0] 410 for (var i=0; i<showblfees_stats.length; i++) { 411 if (showblfees_stats[i][2]!=curr_elem[2]) { 412 if (curr_elem[0] > 0) { 413 stat2.push(curr_elem) 414 } 415 curr_elem = [0,0,showblfees_stats[i][2]] 416 } 417 curr_elem[0] += showblfees_stats[i][0] 418 curr_elem[1] += showblfees_stats[i][1] 419 } 420 if (curr_elem[0] > 0) { 421 stat2.push(curr_elem) 422 } 423 showblfees_stats = stat2 424 } else if (block_fees_spb.checked) { 425 showblfees_stats.sort(function (a, b) { 426 var spb_a = a[1] / a[0] 427 var spb_b = b[1] / b[0] 428 return ( spb_a < spb_b ) ? 1 : ( (spb_a != spb_b) ? -1 : 0 ) 429 }) 430 } 431 432 fees_plot_data = [ { data : [] } ]; 433 434 var plot_options = { 435 xaxis: { position : "top", alignTicksWithAxis: 200 }, 436 yaxis : { position : "right", tickFormatter : function(a) {return a + " SPB"}, labelWidth : 60 }, 437 crosshair : {mode: "xy"}, 438 grid: { hoverable: true, clickable: false }, 439 points: { show:block_fees_points.checked }, 440 lines: {show:true, fill:true} 441 } 442 443 var min_spb, spb 444 totbytes = 0 445 var totfees = 0 446 for (var i=0; i<showblfees_stats.length; i++) { 447 spb = showblfees_stats[i][1] / (showblfees_stats[i][0] / 4) 448 if (i==0) { 449 max_spb = min_spb = spb 450 } else { 451 if (spb>max_spb) max_spb=spb 452 else if (spb<min_spb) min_spb=spb 453 } 454 455 totbytes += (showblfees_stats[i][0] / 4) 456 totfees += showblfees_stats[i][1] 457 fees_plot_data[0].data.push([totbytes, spb]) 458 } 459 460 var avg_fee = totfees / totbytes 461 stat_max_fee.innerText = max_spb.toFixed(0) 462 stat_avg_fee.innerText = avg_fee.toFixed(1) 463 stat_min_fee.innerText = min_spb.toFixed(2) 464 465 if (!block_fees_full.checked) { 466 if (block_fees_25.checked) max_spb /= 4 467 else if (block_fees_5.checked) max_spb /= 20 468 plot_options.yaxis.max = max_spb 469 } 470 471 $.plot($("#block_fees"), fees_plot_data, plot_options) 472 473 $("#block_fees").unbind("plothover") 474 $("#block_fees").bind("plothover", show_fees_handlehover) 475 } catch (e) { 476 console.log('error', e) 477 error_info.innerText = aj.responseText 478 stat_error.style.display = 'block' 479 $("#block_fees").empty() 480 } 481 } 482 } 483 aj.open("GET","blfees.json?height="+last_height, true); 484 aj.send(null); 485 } 486 487 function show_block_fees(height,size,minedby) { 488 last_height = height // for refreshing the chart 489 stat_height.innerText = height 490 stat_block_size.innerText = size 491 stat_mined_by.innerText = minedby 492 show_fees_clicked() 493 }