-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmake-chain.html
More file actions
179 lines (174 loc) · 9.71 KB
/
make-chain.html
File metadata and controls
179 lines (174 loc) · 9.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<html>
<!--
View these functions in action by running the command checkHeight() in your console and then watch the results.
TODO
Ensure that getOpReturns() not only checks the blockchain for op_returns but also checks the oracle
I have to figure out how to validate that the oracle has cosigned everything properly. My assumption was that he would enter a sigchain transaction after every non-oracle transaction attesting to the new state. But if clients require that, then what should the oracle do when a block comes in with multiple transactions in it? Perhaps he should insert a transaction in between each one, but then his cooperation is required for each subsequent op_return transaction after the first one in a block. If I don't require his signature on these transactions at all, then his hashes don't really attest to the full chain, only to his part of it. But maybe that's okay. His signature is only supposed to be a fraud proof of what he did on his chain. The real blockchain doesn't need his attestation. So maybe he is only required to "cosign" sigchain transactions, not op_return transactions. Okay, that will be my new assumption.
Write a function called validateChain() which validates the sigchain created by storeEntry() and alerts the user if it is invalid
-->
<head>
<script>
function makeChain() {
checkHeight();
setTimeout( function() {sortEntries();}, 5000 );
}
function sortEntries( remaining_entries ) {
var all_entries = [];
if ( !remaining_entries ) {
var unsorted_entries = JSON.parse( document.getElementById( "unsorted entries" ).innerHTML );
} else {
var unsorted_entries = remaining_entries;
}
var onetstamp = [];
var othertstamps = [];
var fancytstamp = [];
unsorted_entries.forEach( function( entry ) {
if ( entry[ "timestamp" ].toString() == unsorted_entries[ 0 ][ "timestamp" ].toString() ) {
onetstamp.push( entry );
} else {
othertstamps.push( entry );
}
});
onetstamp.sort( function( a, b ) {
if( b[ "datum" ] < a[ "datum" ] ) {
return 1;
}
if( b[ "datum" ] > a[ "datum" ] ) {
return -1;
}
return 0;
});
onetstamp.forEach( function( entry, index ) {
var fancy_entry = {}
fancy_entry[ "keyhash" ] = entry[ "datum" ].substring( 0, 40 );
fancy_entry[ "msghash" ] = entry[ "datum" ].substring( 40, 80 );
fancy_entry[ "signature" ] = entry[ "datum" ].substring( 80, 160 );
fancy_entry[ "timestamp" ] = entry[ "timestamp" ];
fancy_entry[ "ordinal" ] = index;
fancytstamp.push( fancy_entry );
});
if ( fancytstamp.length > 0 ) {
var newtstamp = document.createElement( "div" );
newtstamp.id = onetstamp[ 0 ][ "timestamp" ].toString();
newtstamp.className = "alt_tstamps";
newtstamp.style.display = "none";
newtstamp.innerHTML = JSON.stringify( fancytstamp );
document.body.append( newtstamp );
}
if ( othertstamps.length > 0 ) {
sortEntries( othertstamps );
} else {
var i; for ( i=0; i<document.getElementsByClassName( "alt_tstamps" ).length; i++ ) {
var local_entries = JSON.parse( document.getElementsByClassName( "alt_tstamps" )[ i ].innerHTML );
local_entries.forEach( function ( entry ) {
all_entries.push( entry );
});
}
document.getElementById( "sorted entries" ).innerHTML = JSON.stringify( all_entries );
}
}
function makeEntries( op_returns, timestamp ) {
var old_entries = JSON.parse( document.getElementById( "unsorted entries" ).innerHTML );
var all_entries = [];
old_entries.forEach( function( item ) {
all_entries.push( item );
});
var entries = [];
op_returns.sort();
op_returns.forEach( function( item ) {
var entry = {}
entry[ "datum" ] = item;
entry[ "timestamp" ] = timestamp;
all_entries.push( entry );
});
document.getElementById( "unsorted entries" ).innerHTML = JSON.stringify( all_entries );
}
function getOpReturn( txid, timestamp ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var transaction = xhttp.responseText;
json = JSON.parse( transaction );
var outputs = json[ "vout" ];
var op_returns = [];
outputs.forEach( function( output ) {
if ( output[ "scriptpubkey_type" ] == "op_return" ) {
if ( output[ "scriptpubkey_asm" ].split( " " )[ 2 ].length == 160 && output[ "scriptpubkey_asm" ].split( " " )[ 2 ].toString().substring( 0, 2 ) == "00" && output[ "scriptpubkey_asm" ].split( " " )[ 2 ].toString().substring( 40, 42 ) == "00" ) {
op_returns.push( output[ "scriptpubkey_asm" ].split( " " )[ 2 ] );
}
}
});
makeEntries( op_returns, timestamp );
}
};
xhttp.open( "GET", "https://blockstream.info/testnet/api/tx/" + txid, true );
xhttp.send();
}
function prepareEntries( blockhash, timestamp ) {
var transactions = "";
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
transactions = JSON.parse( xhttp.responseText );
transactions.forEach( function( txid ) {
getOpReturn( txid, timestamp );
});
}
}
xhttp.open( "GET", "https://blockstream.info/testnet/api/block/" + blockhash + "/txids", true );
xhttp.send();
}
function passTransactions( blockhash ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var meta = JSON.parse( xhttp.responseText );
var timestamp = meta[ "timestamp" ];
var txcount = meta[ "tx_count" ];
adjusted_timestamp = timestamp + 7200;
prepareEntries( blockhash, adjusted_timestamp, txcount );
}
}
xhttp.open( "GET", "https://blockstream.info/testnet/api/block/" + blockhash, true );
xhttp.send();
}
function getChaintip() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var chaintip = xhttp.responseText;
sessionStorage[ "chaintip" ] = chaintip;
}
}
xhttp.open( "GET", "https://blockstream.info/testnet/api/blocks/tip/height", true );
xhttp.send();
}
function checkHeight( blockheight ) {
getChaintip();
if ( !blockheight ) {
blockheight = 2065698;
}
if ( blockheight == sessionStorage[ "chaintip" ] ) {
setTimeout( function() {checkHeight( blockheight );}, 60000 );
} else {
blockheight = blockheight + 1;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var blockhash = xhttp.responseText;
passTransactions( blockhash );
checkHeight( blockheight );
}
}
xhttp.open( "GET", "https://blockstream.info/testnet/api/block-height/" + blockheight, true );
xhttp.send();
}
}
</script>
</head>
<body>
<div id="checker" style="display: none;">[]</div>
<div id="unsorted entries" style="display: none;">[]</div>
<div id="sorted entries">[]</div>
</body>
</html>