mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-22 20:26:50 +00:00
More work on API plus basic block explorer
Added FATJAR packaging support to pom.xml Added some "summary" fields to API calls but more need doing. Corrected path clash from having unnecessary @OpenAPIDefinition annotations. Added API "tags" to group similar calls (address-based, block-related, etc.) Fixed addresses/lastreference/{address} Implemented addresses/lastreference/{address}/unconfirmed Implemented addresses/assets/{address} Added /admin/stop and /admin/uptime API calls. Moved general API info into new src/api/ApiDefinition.java Added CORS support to ApiService Added /transactions/address/{address} and /transactions/block/{signature} Replaced references to test.Common.* to do with repository factory. This fixes issues with building FATJAR due to references to test classes that are omitted from FATJAR. Changes to AccountBalanceData, BlockData and TransactionData to support JAX-RS rendering to JSON. Added getUnconfirmedLastReference() to Account. Added getAllBalances(address) to account repository - returns all asset balances for that address. Added getAllSignaturesInvolvingAddress(address) to account repository but currently only uses TransactionRecipients HSQLDB table. (And even that wasn't automatically populated). Included: very basic block explorer to be opened in browser as a file: block-explorer.html
This commit is contained in:
789
block-explorer.html
Normal file
789
block-explorer.html
Normal file
@@ -0,0 +1,789 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Block Explorer</title>
|
||||
<style>
|
||||
body { color: #404040; font-family: sans-serif; }
|
||||
table { width: 100%; border-collapse: collapse; border: 1px solid #dddddd; margin-bottom: 40px; }
|
||||
tr:nth-child(odd) { background-color: #eeeeee; }
|
||||
th { background-color: #eeeeee; }
|
||||
td { text-align: center; }
|
||||
.sig { font-size: 60%; color: #405906; }
|
||||
.ref { font-size: 60%; color: #609040; }
|
||||
</style>
|
||||
<script>
|
||||
// USEFUL CODE STARTS HERE
|
||||
|
||||
function publicKeyToAddress(publicKey) {
|
||||
var ADDRESS_VERSION = 58; // For normal user accounts starting with "Q"
|
||||
// var ADDRESS_VERSION = 23; // For Automated Transaction accounts starting with "A"
|
||||
|
||||
var publicKeyHashSHA256 = SHA256.digest(publicKey);
|
||||
|
||||
var ripemd160 = new RIPEMD160(); // 'Grandfathered' broken implementation of MD160
|
||||
|
||||
var publicKeyHash = ripemd160.digest(publicKeyHashSHA256);
|
||||
|
||||
var addressArray = new Uint8Array();
|
||||
|
||||
addressArray = appendBuffer(addressArray, [ADDRESS_VERSION]);
|
||||
addressArray = appendBuffer(addressArray, publicKeyHash);
|
||||
|
||||
var checkSum = SHA256.digest(SHA256.digest(addressArray));
|
||||
|
||||
addressArray = appendBuffer(addressArray, checkSum.subarray(0, 4));
|
||||
|
||||
return Base58.encode(addressArray);
|
||||
}
|
||||
|
||||
function renderAddressTransactions(e) {
|
||||
var transactions = e.target.response;
|
||||
|
||||
var address = this.responseURL.split("/")[5];
|
||||
|
||||
if (transactions.length == 0) {
|
||||
document.body.innerHTML += 'No transactions involving address';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '<table id="transactions"><tr><th>Type</th><th>Timestamp</th><th>Creator</th><th>Fee</th><th>Signature</th><th>Reference</th></tr>';
|
||||
|
||||
for (var i=0; i<transactions.length; ++i) {
|
||||
var tx = transactions[i];
|
||||
var txTimestamp = new Date(tx.timestamp).toLocaleString();
|
||||
var txCreatorAddress = publicKeyToAddress(base64ToArray(tx.creatorPublicKey)); // currently base64 but likely to be base58 in the future
|
||||
|
||||
var row = '<tr><td>' + tx.type + '</td>' +
|
||||
'<td>' + txTimestamp + '</td>' +
|
||||
'<td class="addr">' + addressAsLink(txCreatorAddress) + '</td>' +
|
||||
'<td>' + tx.fee + ' QORA</td>' +
|
||||
'<td class="sig">' + Base58.encode(base64ToArray(tx.signature)) + '</td>' +
|
||||
'<td class="ref">' + Base58.encode(base64ToArray(tx.reference)) + '</td></tr>';
|
||||
|
||||
html += row;
|
||||
}
|
||||
|
||||
html += '</table>';
|
||||
|
||||
document.body.innerHTML += html;
|
||||
}
|
||||
|
||||
function renderAddressInfo(e) {
|
||||
var balances = e.target.response;
|
||||
|
||||
var address = this.responseURL.split("/")[5];
|
||||
|
||||
var html = '<h1>Address ' + address + '</h1>';
|
||||
|
||||
html += '<table><tr><th>Asset ID</th><th>Balance</th></tr>';
|
||||
|
||||
for (var i=0; i<balances.length; ++i) {
|
||||
var balanceInfo = balances[i];
|
||||
|
||||
html += '<tr><td>' + balanceInfo.assetId + '</td><td>' + balanceInfo.balance + '</td></tr>';
|
||||
}
|
||||
|
||||
html += '</table>';
|
||||
|
||||
document.body.innerHTML = html;
|
||||
|
||||
XHR({
|
||||
url: "http://localhost:9085/transactions/address/" + address,
|
||||
onload: renderAddressTransactions,
|
||||
responseType: "json"
|
||||
});
|
||||
}
|
||||
|
||||
function fetchAddressInfo(address) {
|
||||
XHR({
|
||||
url: "http://localhost:9085/addresses/assets/" + address,
|
||||
onload: renderAddressInfo,
|
||||
responseType: "json"
|
||||
});
|
||||
}
|
||||
|
||||
function addressAsLink(address) {
|
||||
return '<a href="#" onclick="fetchAddressInfo(' + "'" + address + "'" + ')">' + address + '</a>';
|
||||
}
|
||||
|
||||
function renderBlockTransactions(e) {
|
||||
var transactions = e.target.response;
|
||||
|
||||
if (transactions.length == 0) {
|
||||
document.body.innerHTML += 'No transactions in block';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '<table id="transactions"><tr><th>Type</th><th>Timestamp</th><th>Creator</th><th>Fee</th><th>Signature</th><th>Reference</th></tr>';
|
||||
|
||||
for (var i=0; i<transactions.length; ++i) {
|
||||
var tx = transactions[i];
|
||||
var txTimestamp = new Date(tx.timestamp).toLocaleString();
|
||||
var txCreatorAddress = publicKeyToAddress(base64ToArray(tx.creatorPublicKey)); // currently base64 but likely to be base58 in the future
|
||||
|
||||
var row = '<tr><td>' + tx.type + '</td>' +
|
||||
'<td>' + txTimestamp + '</td>' +
|
||||
'<td class="addr">' + addressAsLink(txCreatorAddress) + '</td>' +
|
||||
'<td>' + tx.fee + ' QORA</td>' +
|
||||
'<td class="sig">' + Base58.encode(base64ToArray(tx.signature)) + '</td>' +
|
||||
'<td class="ref">' + Base58.encode(base64ToArray(tx.reference)) + '</td></tr>';
|
||||
|
||||
html += row;
|
||||
}
|
||||
|
||||
html += '</table>';
|
||||
|
||||
document.body.innerHTML += html;
|
||||
}
|
||||
|
||||
function renderBlockInfo(e) {
|
||||
var blockData = e.target.response;
|
||||
|
||||
// These properties are currently emitted as base64 by API but likely to be base58 in the future, so convert them
|
||||
var props = [ "signature", "reference", "transactionsSignature", "generatorPublicKey", "generatorSignature" ];
|
||||
for (var i=0; i<props.length; ++i) {
|
||||
var p = props[i];
|
||||
blockData[p] = Base58.encode(base64ToArray(blockData[p]));
|
||||
}
|
||||
|
||||
// convert generator public key into address
|
||||
blockData.generator = publicKeyToAddress(base64ToArray(blockData.generatorPublicKey)); // currently base64 but likely to be base58 in the future
|
||||
|
||||
var html = '<h1>Block ' + blockData.height + '</h1>';
|
||||
html += '<table id="block"><tr><th>Property</th><th>Value</th></tr>';
|
||||
|
||||
for (var p in blockData) {
|
||||
html += '<tr><td>' + p + '</td>';
|
||||
|
||||
if (p.indexOf("ignature") != -1) {
|
||||
html += '<td class="sig">';
|
||||
} else if (p.indexOf("eference") != -1) {
|
||||
html += '<td class="ref">';
|
||||
} else {
|
||||
html += '<td>';
|
||||
}
|
||||
|
||||
if (p == "generator") {
|
||||
html += addressAsLink(blockData[p]);
|
||||
} else {
|
||||
html += blockData[p];
|
||||
}
|
||||
|
||||
if (p.indexOf("ees") != -1)
|
||||
html += " QORA";
|
||||
|
||||
html += '</td></tr>';
|
||||
}
|
||||
|
||||
html += '</table>';
|
||||
|
||||
document.body.innerHTML = html;
|
||||
|
||||
// Fetch block's transactions
|
||||
XHR({
|
||||
url: "http://localhost:9085/transactions/block/" + blockData.signature,
|
||||
onload: renderBlockTransactions,
|
||||
responseType: "json"
|
||||
});
|
||||
}
|
||||
|
||||
function fetchBlockInfo(height) {
|
||||
XHR({
|
||||
url: "http://localhost:9085/blocks/byheight/" + height,
|
||||
onload: renderBlockInfo,
|
||||
responseType: "json"
|
||||
});
|
||||
}
|
||||
|
||||
function listBlock(e) {
|
||||
var blockData = e.target.response;
|
||||
|
||||
var ourHeight = blockData.height;
|
||||
var blockTimestamp = new Date(blockData.timestamp).toLocaleString();
|
||||
var blockGeneratorAddress = publicKeyToAddress(base64ToArray(blockData.generatorPublicKey)); // currently base64 but likely to be base58 in the future
|
||||
|
||||
var ourRow = document.createElement('TR');
|
||||
ourRow.innerHTML = '<td><a href="#" onclick="fetchBlockInfo(' + ourHeight + ')">' + ourHeight + '</a></td>' +
|
||||
'<td>' + blockTimestamp + '</td>' +
|
||||
'<td class="addr">' + addressAsLink(blockGeneratorAddress) + '</td>' +
|
||||
'<td>' + blockData.generatingBalance + '</td>' +
|
||||
'<td>' + blockData.transactionCount + '</td>' +
|
||||
'<td>' + blockData.totalFees + ' QORA</td>';
|
||||
|
||||
var table = document.getElementById('blocks');
|
||||
var rows = table.getElementsByTagName('TR');
|
||||
for (var r = 1; r < rows.length; ++r)
|
||||
if (ourHeight > rows[r].cells[0].innerText) {
|
||||
table.insertBefore(ourRow, rows[r]);
|
||||
return;
|
||||
}
|
||||
|
||||
table.appendChild(ourRow);
|
||||
}
|
||||
|
||||
function showShutdown() {
|
||||
document.body.innerHTML = '<h1>Shutdown</h1>';
|
||||
}
|
||||
|
||||
function shutdownAPI() {
|
||||
XHR({
|
||||
url: "http://localhost:9085/admin/stop",
|
||||
onload: showShutdown,
|
||||
responseType: "json"
|
||||
});
|
||||
}
|
||||
|
||||
function listBlocksFrom(height) {
|
||||
document.body.innerHTML = '<h1>Blocks</h1>';
|
||||
|
||||
document.body.innerHTML += '<table id="blocks"><tr><th>Height</th><th>Time</th><th>Generator</th><th>Gen.Balance</th><th>TX</th><th>Fees</th></tr></table>';
|
||||
|
||||
if (height > 20)
|
||||
document.body.innerHTML += '<a href="#" onclick="listBlocksFrom(' + (height - 20) + ')">Previous blocks...</a>';
|
||||
|
||||
document.body.innerHTML += '<p><a href="#" onclick="fetchBlockInfo(356928)">Block with lots of transactions</a>';
|
||||
|
||||
document.body.innerHTML += '<p><a href="#" onclick="shutdownAPI()">Shutdown</a>';
|
||||
|
||||
for (var h = height; h > 0 && h >= height - 20; --h)
|
||||
XHR({
|
||||
url: "http://localhost:9085/blocks/byheight/" + h,
|
||||
onload: listBlock,
|
||||
responseType: "json"
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function initialBlocks(e) {
|
||||
var height = e.target.response;
|
||||
console.log("initial block height: " + height);
|
||||
|
||||
listBlocksFrom(height);
|
||||
}
|
||||
|
||||
function windowOnLoad() {
|
||||
XHR({
|
||||
url: "http://localhost:9085/blocks/height",
|
||||
onload: initialBlocks,
|
||||
responseType: "json"
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('load', windowOnLoad, false);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// UTILITY FUNCTIONS BELOW (Base64, Base58, SHA256, etc.)
|
||||
|
||||
function base64ToArray(base64) {
|
||||
var raw = window.atob(base64);
|
||||
var rawLength = raw.length;
|
||||
var array = new Uint8Array(new ArrayBuffer(rawLength));
|
||||
|
||||
for(i = 0; i < rawLength; i++) {
|
||||
array[i] = raw.charCodeAt(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
function appendBuffer (buffer1, buffer2) {
|
||||
buffer1 = new Uint8Array(buffer1);
|
||||
buffer2 = new Uint8Array(buffer2);
|
||||
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
|
||||
tmp.set(buffer1, 0);
|
||||
tmp.set(buffer2, buffer1.byteLength);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// BASE58
|
||||
|
||||
(function() {
|
||||
var ALPHABET, ALPHABET_MAP, Base58, i;
|
||||
|
||||
Base58 = (typeof module !== "undefined" && module !== null ? module.exports : void 0) || (window.Base58 = {});
|
||||
|
||||
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
ALPHABET_MAP = {};
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < ALPHABET.length) {
|
||||
ALPHABET_MAP[ALPHABET.charAt(i)] = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
Base58.encode = function(buffer) {
|
||||
var carry, digits, j;
|
||||
if (buffer.length === 0) {
|
||||
return "";
|
||||
}
|
||||
i = void 0;
|
||||
j = void 0;
|
||||
digits = [0];
|
||||
i = 0;
|
||||
while (i < buffer.length) {
|
||||
j = 0;
|
||||
while (j < digits.length) {
|
||||
digits[j] <<= 8;
|
||||
j++;
|
||||
}
|
||||
digits[0] += buffer[i];
|
||||
carry = 0;
|
||||
j = 0;
|
||||
while (j < digits.length) {
|
||||
digits[j] += carry;
|
||||
carry = (digits[j] / 58) | 0;
|
||||
digits[j] %= 58;
|
||||
++j;
|
||||
}
|
||||
while (carry) {
|
||||
digits.push(carry % 58);
|
||||
carry = (carry / 58) | 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
while (buffer[i] === 0 && i < buffer.length - 1) {
|
||||
digits.push(0);
|
||||
i++;
|
||||
}
|
||||
return digits.reverse().map(function(digit) {
|
||||
return ALPHABET[digit];
|
||||
}).join("");
|
||||
};
|
||||
|
||||
Base58.decode = function(string) {
|
||||
var bytes, c, carry, j;
|
||||
if (string.length === 0) {
|
||||
return new (typeof Uint8Array !== "undefined" && Uint8Array !== null ? Uint8Array : Buffer)(0);
|
||||
}
|
||||
i = void 0;
|
||||
j = void 0;
|
||||
bytes = [0];
|
||||
i = 0;
|
||||
while (i < string.length) {
|
||||
c = string[i];
|
||||
if (!(c in ALPHABET_MAP)) {
|
||||
throw "Base58.decode received unacceptable input. Character '" + c + "' is not in the Base58 alphabet.";
|
||||
}
|
||||
j = 0;
|
||||
while (j < bytes.length) {
|
||||
bytes[j] *= 58;
|
||||
j++;
|
||||
}
|
||||
bytes[0] += ALPHABET_MAP[c];
|
||||
carry = 0;
|
||||
j = 0;
|
||||
while (j < bytes.length) {
|
||||
bytes[j] += carry;
|
||||
carry = bytes[j] >> 8;
|
||||
bytes[j] &= 0xff;
|
||||
++j;
|
||||
}
|
||||
while (carry) {
|
||||
bytes.push(carry & 0xff);
|
||||
carry >>= 8;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
while (string[i] === "1" && i < string.length - 1) {
|
||||
bytes.push(0);
|
||||
i++;
|
||||
}
|
||||
return new (typeof Uint8Array !== "undefined" && Uint8Array !== null ? Uint8Array : Buffer)(bytes.reverse());
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// SHA256
|
||||
|
||||
SHA256 = {};
|
||||
|
||||
SHA256.K = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
|
||||
0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
|
||||
0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
|
||||
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
||||
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
||||
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
||||
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
||||
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
|
||||
|
||||
// The digest function returns the hash value (digest)
|
||||
// as a 32 byte (typed) array.
|
||||
// message: the string or byte array to hash
|
||||
SHA256.digest = function(message) {
|
||||
var h0 = 0x6a09e667;
|
||||
var h1 = 0xbb67ae85;
|
||||
var h2 = 0x3c6ef372;
|
||||
var h3 = 0xa54ff53a;
|
||||
var h4 = 0x510e527f;
|
||||
var h5 = 0x9b05688c;
|
||||
var h6 = 0x1f83d9ab;
|
||||
var h7 = 0x5be0cd19;
|
||||
var K = SHA256.K;
|
||||
if (typeof message == 'string') {
|
||||
var s = unescape(encodeURIComponent(message)); // UTF-8
|
||||
message = new Uint8Array(s.length);
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
message[i] = s.charCodeAt(i) & 0xff;
|
||||
}
|
||||
}
|
||||
var length = message.length;
|
||||
var byteLength = Math.floor((length + 72) / 64) * 64;
|
||||
var wordLength = byteLength / 4;
|
||||
var bitLength = length * 8;
|
||||
var m = new Uint8Array(byteLength);
|
||||
m.set(message);
|
||||
m[length] = 0x80;
|
||||
m[byteLength - 4] = bitLength >>> 24;
|
||||
m[byteLength - 3] = (bitLength >>> 16) & 0xff;
|
||||
m[byteLength - 2] = (bitLength >>> 8) & 0xff;
|
||||
m[byteLength - 1] = bitLength & 0xff;
|
||||
var words = new Int32Array(wordLength);
|
||||
var byteIndex = 0;
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var word = m[byteIndex++] << 24;
|
||||
word |= m[byteIndex++] << 16;
|
||||
word |= m[byteIndex++] << 8;
|
||||
word |= m[byteIndex++];
|
||||
words[i] = word;
|
||||
}
|
||||
var w = new Int32Array(64);
|
||||
for (var j = 0; j < wordLength; j += 16) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
w[i] = words[j + i];
|
||||
}
|
||||
for (i = 16; i < 64; i++) {
|
||||
var v = w[i - 15];
|
||||
var s0 = (v >>> 7) | (v << 25);
|
||||
s0 ^= (v >>> 18) | (v << 14);
|
||||
s0 ^= (v >>> 3);
|
||||
v = w[i - 2];
|
||||
var s1 = (v >>> 17) | (v << 15);
|
||||
s1 ^= (v >>> 19) | (v << 13);
|
||||
s1 ^= (v >>> 10);
|
||||
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffff;
|
||||
}
|
||||
var a = h0;
|
||||
var b = h1;
|
||||
var c = h2;
|
||||
var d = h3;
|
||||
var e = h4;
|
||||
var f = h5;
|
||||
var g = h6;
|
||||
var h = h7;
|
||||
for (i = 0; i < 64; i++) {
|
||||
s1 = (e >>> 6) | (e << 26);
|
||||
s1 ^= (e >>> 11) | (e << 21);
|
||||
s1 ^= (e >>> 25) | (e << 7);
|
||||
var ch = (e & f) ^ (~e & g);
|
||||
var temp1 = (h + s1 + ch + K[i] + w[i]) & 0xffffffff;
|
||||
s0 = (a >>> 2) | (a << 30);
|
||||
s0 ^= (a >>> 13) | (a << 19);
|
||||
s0 ^= (a >>> 22) | (a << 10);
|
||||
var maj = (a & b) ^ (a & c) ^ (b & c);
|
||||
var temp2 = (s0 + maj) & 0xffffffff;
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = (d + temp1) & 0xffffffff;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = (temp1 + temp2) & 0xffffffff;
|
||||
}
|
||||
h0 = (h0 + a) & 0xffffffff;
|
||||
h1 = (h1 + b) & 0xffffffff;
|
||||
h2 = (h2 + c) & 0xffffffff;
|
||||
h3 = (h3 + d) & 0xffffffff;
|
||||
h4 = (h4 + e) & 0xffffffff;
|
||||
h5 = (h5 + f) & 0xffffffff;
|
||||
h6 = (h6 + g) & 0xffffffff;
|
||||
h7 = (h7 + h) & 0xffffffff;
|
||||
}
|
||||
var hash = new Uint8Array(32);
|
||||
for (i = 0; i < 4; i++) {
|
||||
hash[i] = (h0 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 4] = (h1 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 8] = (h2 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 12] = (h3 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 16] = (h4 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 20] = (h5 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 24] = (h6 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 28] = (h7 >>> (8 * (3 - i))) & 0xff;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// The hash function returns the hash value as a hex string.
|
||||
// message: the string or byte array to hash
|
||||
SHA256.hash = function(message) {
|
||||
var digest = SHA256.digest(message);
|
||||
var hex = '';
|
||||
for (i = 0; i < digest.length; i++) {
|
||||
var s = '0' + digest[i].toString(16);
|
||||
hex += s.length > 2 ? s.substring(1) : s;
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function XHR(options) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
if ("form" in options) {
|
||||
options.data = new FormData(options.form);
|
||||
|
||||
if ( !("url" in options) )
|
||||
options.url = options.form.action;
|
||||
|
||||
if ( !("method" in options) && ("method" in options.form) )
|
||||
options.method = options.form.method;
|
||||
}
|
||||
|
||||
if ("json" in options) {
|
||||
options.data = JSON.stringify(options.json);
|
||||
options.method = "POST";
|
||||
options.responseType = "json";
|
||||
}
|
||||
|
||||
if ( !("method" in options) )
|
||||
options.method = "GET";
|
||||
|
||||
if ("responseType" in options)
|
||||
try {
|
||||
xhr.responseType = options.responseType;
|
||||
} catch(e) {
|
||||
console.log("XMLHttpRequest doesn't support responseType of '" + options.responseType + "'");
|
||||
xhr.bodgeJSON = true;
|
||||
}
|
||||
|
||||
if ("onload" in options) {
|
||||
if (options.responseType == "json" && xhr.bodgeJSON)
|
||||
xhr.addEventListener("load", function(e) { var e = { target: { response: JSON.parse(e.target.response) } }; options.onload(e) }, false);
|
||||
else
|
||||
xhr.addEventListener("load", options.onload, false);
|
||||
}
|
||||
|
||||
xhr.open(options.method, options.url);
|
||||
|
||||
if ("json" in options)
|
||||
xhr.setRequestHeader( "Content-Type", "application/json" );
|
||||
|
||||
if ("contentType" in options)
|
||||
xhr.setRequestHeader( "Content-Type", options.contentType );
|
||||
|
||||
xhr.send(options.data);
|
||||
|
||||
return xhr;
|
||||
}
|
||||
|
||||
|
||||
// RIPEMD160
|
||||
|
||||
|
||||
var RIPEMD160 = (function () {
|
||||
function RIPEMD160() {
|
||||
this.MDbuf = [];
|
||||
this.MDbuf[0] = 1732584193;
|
||||
this.MDbuf[1] = -271733879;
|
||||
this.MDbuf[2] = -1732584194;
|
||||
this.MDbuf[3] = 271733878;
|
||||
this.MDbuf[4] = -1009589776;
|
||||
this.working = new Int32Array(16);
|
||||
|
||||
this.working_ptr = 0;
|
||||
this.msglen = 0;
|
||||
}
|
||||
RIPEMD160.prototype.reset = function () {
|
||||
this.MDbuf = [];
|
||||
this.MDbuf[0] = 1732584193;
|
||||
this.MDbuf[1] = -271733879;
|
||||
this.MDbuf[2] = -1732584194;
|
||||
this.MDbuf[3] = 271733878;
|
||||
this.MDbuf[4] = -1009589776;
|
||||
this.working = new Int32Array(16);
|
||||
this.working_ptr = 0;
|
||||
this.msglen = 0;
|
||||
};
|
||||
RIPEMD160.prototype.compress = function (X) {
|
||||
var index = 0;
|
||||
var a;
|
||||
var b;
|
||||
var c;
|
||||
var d;
|
||||
var e;
|
||||
var A;
|
||||
var B;
|
||||
var C;
|
||||
var D;
|
||||
var E;
|
||||
var temp;
|
||||
var s;
|
||||
A = a = this.MDbuf[0];
|
||||
B = b = this.MDbuf[1];
|
||||
C = c = this.MDbuf[2];
|
||||
D = d = this.MDbuf[3];
|
||||
E = e = this.MDbuf[4];
|
||||
for (; index < 16; index++) {
|
||||
temp = a + (b ^ c ^ d) + X[RIPEMD160.IndexArray[0][index]];
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + (B ^ (C | ~D)) + X[RIPEMD160.IndexArray[1][index]] + 1352829926;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 32; index++) {
|
||||
temp = a + ((b & c) | (~b & d)) + X[RIPEMD160.IndexArray[0][index]] + 1518500249;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + ((B & D) | (C & ~D)) + X[RIPEMD160.IndexArray[1][index]] + 1548603684;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 48; index++) {
|
||||
temp = a + ((b | ~c) ^ d) + X[RIPEMD160.IndexArray[0][index]] + 1859775393;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + ((B | ~C) ^ D) + X[RIPEMD160.IndexArray[1][index]] + 1836072691;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 64; index++) {
|
||||
temp = a + ((b & d) | (c & ~d)) + X[RIPEMD160.IndexArray[0][index]] + -1894007588;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + ((B & C) | (~B & D)) + X[RIPEMD160.IndexArray[1][index]] + 2053994217;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 80; index++) {
|
||||
temp = a + (b ^ (c | ~d)) + X[RIPEMD160.IndexArray[0][index]] + -1454113458;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + (B ^ C ^ D) + X[RIPEMD160.IndexArray[1][index]];
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
D += c + this.MDbuf[1];
|
||||
this.MDbuf[1] = this.MDbuf[2] + d + E;
|
||||
this.MDbuf[2] = this.MDbuf[3] + e + A;
|
||||
this.MDbuf[3] = this.MDbuf[4] + a + B;
|
||||
this.MDbuf[4] = this.MDbuf[0] + b + C;
|
||||
this.MDbuf[0] = D;
|
||||
};
|
||||
RIPEMD160.prototype.MDfinish = function (array, lswlen, mswlen) {
|
||||
var X = array;
|
||||
X[(lswlen >> 2) & 15] ^= 1 << (((lswlen & 3) << 3) + 7);
|
||||
if (((lswlen & 63) > 55)) {
|
||||
this.compress(X);
|
||||
for (var i = 0; i < 14; i++) {
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
X[14] = lswlen << 3;
|
||||
X[15] = (lswlen >> 29) | (mswlen << 3);
|
||||
this.compress(X);
|
||||
};
|
||||
RIPEMD160.prototype.update = function (input) {
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
this.working[this.working_ptr >> 2] ^= input[i] << ((this.working_ptr & 3) << 3);
|
||||
this.working_ptr++;
|
||||
if ((this.working_ptr == 64)) {
|
||||
this.compress(this.working);
|
||||
for (var j = 0; j < 16; j++) {
|
||||
this.working[j] = 0;
|
||||
}
|
||||
this.working_ptr = 0;
|
||||
}
|
||||
}
|
||||
this.msglen += input.length;
|
||||
};
|
||||
RIPEMD160.prototype.digestBin = function () {
|
||||
this.MDfinish(this.working, this.msglen, 0);
|
||||
//var res = new Int8Array();
|
||||
var res = [];
|
||||
for (var i = 0; i < 20; i++) {
|
||||
res[i] = ((this.MDbuf[i >> 2] >>> ((i & 3) << 3)) & 255);
|
||||
}
|
||||
return new Uint8Array(res);
|
||||
};
|
||||
RIPEMD160.prototype.digest = function (input) {
|
||||
this.update(new Int8Array(input));
|
||||
return this.digestBin();
|
||||
};
|
||||
RIPEMD160.ArgArray = [[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]];
|
||||
RIPEMD160.IndexArray = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]];
|
||||
return RIPEMD160;
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Making initial call to API...
|
||||
<p>
|
||||
If nothing happens then check API is running!
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user