Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Commit

Permalink
Version 532. Improved Micropay flow and blockchain tracking.
Browse files Browse the repository at this point in the history
  • Loading branch information
n-y-z-o committed Jul 7, 2019
1 parent fc51f4f commit cdab238
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/main/java/co/nyzo/verifier/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class Version {

private static final int version = 531;
private static final int version = 532;

public static int getVersion() {

Expand Down
18 changes: 18 additions & 0 deletions src/main/java/co/nyzo/verifier/client/ClientDataManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class ClientDataManager {

private static final long meshUpdateInterval = 1000L * 60L * 5L; // 5 minutes
private static final long blockUpdateInterval = 1000L * 4L; // 4 seconds
private static final long minimumReinitializationInterval = 1000L * 60L * 10L; // 10 minutes
private static final long reinitializationThreshold = 1000L * 60L * 10L; // 10 minutes; about 86 blocks

public static void start() {

Expand Down Expand Up @@ -48,6 +50,7 @@ public void run() {

long lastMeshUpdateTimestamp = 0L;
long lastBlockUpdateTimestamp = 0L;
long lastReinitializationTimestamp = System.currentTimeMillis();

while (!UpdateUtil.shouldTerminate()) {

Expand All @@ -63,6 +66,21 @@ public void run() {
requestBlockWithVotes();
}

// Reinitialize the frozen edge, if necessary. Both checks must be performed to avoid continuously
// reinitializing if the blockchain is stalled.
long timeSinceVerification = System.currentTimeMillis() -
BlockManager.getFrozenEdge().getVerificationTimestamp();
long timeSinceReinitialization = System.currentTimeMillis() - lastReinitializationTimestamp;
if (timeSinceVerification > reinitializationThreshold &&
timeSinceReinitialization > minimumReinitializationInterval) {
System.out.println(ConsoleColor.Yellow.background() + "reinitializing frozen edge, height=" +
BlockManager.getFrozenEdgeHeight() + ConsoleColor.reset);
ChainInitializationManager.initializeFrozenEdge(trustedEntryPoints);
System.out.println(ConsoleColor.Yellow.background() + "reinitialized frozen edge, height=" +
BlockManager.getFrozenEdgeHeight() + ConsoleColor.reset);
lastReinitializationTimestamp = System.currentTimeMillis();
}

// Sleep for a short time to keep the loop from running too tightly.
ThreadUtil.sleep(300L);
}
Expand Down
37 changes: 15 additions & 22 deletions src/main/java/co/nyzo/verifier/micropay/MicropayController.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ public class MicropayController {

private static final String dataRootDirectory = PreferencesUtil.get(dataRootKey);
public static final String clientPingEndpoint = "/micropay/ping";
public static final String serverPingEndpoint = "/micropay/ping";
public static final String clientAuthorizationEndpoint = "/micropay/authorize";
public static final String pingResponse = "hello, Micropay user!";
public static final String clientPingResponse = "hello, Micropay user!";

public static Map<String, EndpointMethod> buildEndpointMap() {

Expand Down Expand Up @@ -81,19 +82,24 @@ private static void process(File[] files, String rootFilePath, Map<String, Endpo
}

public static EndpointResponse clientPingPage(Map<String, String> queryParameters, byte[] sourceIpAddress) {
EndpointResponse response = new EndpointResponse((pingResponse + " " + IpUtil.addressAsString(sourceIpAddress))
.getBytes(StandardCharsets.UTF_8));
EndpointResponse response = new EndpointResponse((clientPingResponse + " " +
IpUtil.addressAsString(sourceIpAddress)).getBytes(StandardCharsets.UTF_8));
response.setHeader("Access-Control-Allow-Origin", "*");
return response;
}

public static EndpointResponse serverPingPage(Map<String, String> queryParameters, byte[] sourceIpAddress) {
return new EndpointResponse(("hello, " + IpUtil.addressAsString(sourceIpAddress))
.getBytes(StandardCharsets.UTF_8));
}

public static EndpointResponse clientAuthorizationPage(Map<String, String> queryParameters, byte[] sourceIpAddress) {

// Make the HTML page.
Html html = new Html();
Html html = (Html) new Html().attr("lang", "en");

// Add the head and body to the page.
Head head = (Head) html.add(new Head().attr("lang", "en"));
Head head = (Head) html.add(new Head().addStandardMetadata());
head.add(new Title("Nyzo Micropay authorization"));
Body body = (Body) html.add(new Body().attr("style", "font-family: sans-serif; text-align: center"));

Expand All @@ -108,23 +114,10 @@ public static EndpointResponse clientAuthorizationPage(Map<String, String> query

// Add the header and Micropay amount and receiver.
body.add(new H1("Nyzo Micropay"));
NyzoStringMicropay micropay = (NyzoStringMicropay) decodedString;
body.add(new P("amount: " + PrintUtil.printAmount(micropay.getAmount())).attr("style",
"font-size: larger; font-weight: bold;"));
body.add(new P("receiver ID: " +
NyzoStringEncoder.encode(new NyzoStringPublicIdentifier(micropay.getReceiverIdentifier())))
.attr("style", "word-break: break-all;"));

// Add the sender data.
String senderData =
WebUtil.sanitizeString(ClientTransactionUtil.senderDataString(micropay.getSenderData()).trim());
if (senderData.isEmpty()) {
senderData = "<span style=\"font-style: italic\">empty</span>";
}
body.add(new P("sender data: " + senderData));

// If Micropay is configured correctly and the transaction amount is less than the Micropay maximum,
// create the transaction. Otherwise, display the issue.
NyzoStringMicropay micropay = (NyzoStringMicropay) decodedString;
String error = "";
NyzoStringPrivateSeed senderSeed = getSenderSeed();
long maximumAmount = getMaximumTransactionAmountMicronyzos();
Expand Down Expand Up @@ -163,9 +156,9 @@ public static EndpointResponse clientAuthorizationPage(Map<String, String> query
WebUtil.acceptButtonStyle + " display: table; margin-bottom: 0.5rem;"));
}

// The "cancel" link is just the raw callback.
body.add(new A().attr("href", callback).addRaw("cancel").attr("style", WebUtil.cancelButtonStyle +
" display: table;"));
// The "cancel" link has a "cancel=y" parameter instead of a transaction parameter.
body.add(new A().attr("href", callback + "?cancel=y").addRaw("cancel").attr("style",
WebUtil.cancelButtonStyle + " display: table;"));
}

return new EndpointResponse(html.renderByteArray());
Expand Down
51 changes: 33 additions & 18 deletions src/main/java/co/nyzo/verifier/micropay/MicropayEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,23 @@ public EndpointResponse renderByteArray(Map<String, String> queryParameters, byt
}
} else {
// Otherwise, present the authorization page.
result = serverAuthorizationPage(transactionProblem.toString(), sourceIpAddress);
String cancelParameter = queryParameters.getOrDefault("cancel", "").toLowerCase();
boolean isCancellation = cancelParameter.equals("y") || cancelParameter.equals("yes");
result = serverAuthorizationPage(transactionProblem.toString(), sourceIpAddress, isCancellation);
}

EndpointResponse response = new EndpointResponse(result);
response.setHeader("Content-type", contentType);
return response;
}

private byte[] serverAuthorizationPage(String transactionProblem, byte[] sourceIpAddress) {
private byte[] serverAuthorizationPage(String transactionProblem, byte[] sourceIpAddress, boolean isCancellation) {

// Make the HTML page.
Html html = new Html();
Html html = (Html) new Html().attr("lang", "en");

// Add the head and body to the page.
Head head = (Head) html.add(new Head().attr("lang", "en"));
Head head = (Head) html.add(new Head().addStandardMetadata());
head.add(new Title("Nyzo Micropay authorization"));
Body body = (Body) html.add(new Body().attr("style", "font-family: sans-serif; text-align: center"));

Expand All @@ -153,24 +155,36 @@ private byte[] serverAuthorizationPage(String transactionProblem, byte[] sourceI
// Add the header.
body.add(new H3("Nyzo Micropay premium content"));

// Add the problem with a previous transaction, if present.
// Add problem/cancellation notices, if relevant. Otherwise, build the redirect.
String redirect = "";
String authorizationEndpoint = MicropayController.clientAuthorizationEndpoint + "?micropay=" +
NyzoStringEncoder.encode(micropayString) + "&callback=" + MicropayServer.getCallbackBaseUrl() + path;
if (transactionProblem != null && !transactionProblem.isEmpty()) {
body.add(new H3(transactionProblem).attr("style", "color: red;"));
} else if (isCancellation) {
body.add(new H3("Transaction was cancelled").attr("style", "color: red;"));
} else {
redirect = "window.location.replace(protocol + '://127.0.0.1' + port + '" + authorizationEndpoint + "');";
}

// Add the authorization link.
body.add(new A().attr("id", "authorizeLink").attr("style", WebUtil.acceptButtonStyle + " opacity: 0.4;")
.addRaw(PrintUtil.printAmount(amount)));
// Add the "scanning" message and authorization link.
body.add(new A().attr("id", "authorizeLink").attr("style", WebUtil.acceptButtonStyle +
" opacity: 0.4; display: table; margin-top: 1rem;")
.addRaw("Access this content for " + PrintUtil.printAmount(amount)));
body.add(new P("Scanning for Micropay client...").attr("id", "scanningMessage"));

// Add the error message. This is only displayed if the following script is unable to find a client.
body.add(new P().attr("id", "errorMessage").addRaw("Unable to determine Nyzo Micropay client port")
.attr("style", "color: red; display: none;"));
.attr("style", "color: red; visibility: hidden;"));

// Add a simple script that checks the most common ports and activates the link on the appropriate port.
String authorizationEndpoint = MicropayController.clientAuthorizationEndpoint + "?micropay=" +
NyzoStringEncoder.encode(micropayString) + "&callback=" + MicropayServer.getCallbackBaseUrl() + path;
// Add a link to return to the root of the site.
body.add(new A().attr("href", "/").addRaw("&larr; return to main page"));

// Add a simple script that checks the most common ports. If this is a first attempt (no transaction provided),
// the script redirects to the local authorization page.
String pingEndpoint = MicropayController.clientPingEndpoint;
String pingResponse = MicropayController.pingResponse;
String pingResponse = MicropayController.clientPingResponse;

body.add(new Script("" +
"var successful = false;" +
"function sendPing(port, protocol) {" +
Expand All @@ -180,9 +194,10 @@ private byte[] serverAuthorizationPage(String transactionProblem, byte[] sourceI
" if (this.responseText.startsWith('" + pingResponse + "')) {" +
" successful = true;" +
" var link = document.getElementById('authorizeLink');" +
" link.href = protocol + '://127.0.0.1' + port + '" + authorizationEndpoint + "';\n" +
" link.style.opacity = 1.0;\n" +
" document.getElementById('errorMessage').style.display = 'none';\n" +
" link.href = protocol + '://127.0.0.1' + port + '" + authorizationEndpoint + "';" +
" link.style.opacity = 1.0;" +
" document.getElementById('errorMessage').style.visibility = 'hidden';" + redirect +
" document.getElementById('scanningMessage').style.visibility = 'hidden';" +
" }" +
" };" +

Expand All @@ -202,10 +217,10 @@ private byte[] serverAuthorizationPage(String transactionProblem, byte[] sourceI

"var interval = setInterval(function() {" +
" if (successful) {\n" +
" document.getElementById('errorMessage').style.display = 'none';\n" +
" document.getElementById('errorMessage').style.visibility = 'hidden';" +
" clearInterval(interval);" +
" } else {\n" +
" document.getElementById('errorMessage').style.display = 'block';" +
" document.getElementById('errorMessage').style.visibility = 'visible';" +
" sendPings();" +
" }\n" +
"}, 3000);"));
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/co/nyzo/verifier/web/CycleController.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ public class CycleController {
public static EndpointResponse page(Map<String, String> queryParameters, byte[] sourceIpAddress) {

// Make the HTML page.
Html html = new Html();
Html html = (Html) new Html().attr("lang", "en");

// Add the head and body to the page.
Head head = (Head) html.add(new Head());
Head head = (Head) html.add(new Head().addStandardMetadata());
Body body = (Body) html.add(new Body().attr("style", "font-family: sans-serif; text-align: center"));

// Add the div cycle container and the cycle content.
Expand Down
7 changes: 2 additions & 5 deletions src/main/java/co/nyzo/verifier/web/SentinelController.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@ public class SentinelController {
public static EndpointResponse page(Map<String, String> queryParameters, byte[] sourceIpAddress) {

// Make the HTML page.
Html html = new Html();
Html html = (Html) new Html().attr("lang", "en");

// Add the head and body to the page.
Head head = (Head) html.add(new Head());
Head head = (Head) html.add(new Head().addStandardMetadata());
Body body = (Body) html.add(new Body().attr("style", "font-family: sans-serif; text-align: center"));

// Add standard metadata to the head.
head.addStandardMetadata();

// Add the container div to the page and content to the container div.
Div container = (Div) body.add(new Div().attr("id", "container").attr("style", "display: inline-block;"));
container.add(divContent());
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/co/nyzo/verifier/web/WebListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ public void handle(HttpExchange httpExchange) throws IOException {
System.out.println("path: " + path(httpExchange));
System.out.println("parameters: " + parameters(httpExchange));


// Render the page.
EndpointResponse response;
int statusCode;
if (endpoint == null) {
response = new EndpointResponse("page not found".getBytes(StandardCharsets.UTF_8));
statusCode = 404;
} else {
response = endpoint.renderByteArray(parameters,
httpExchange.getRemoteAddress().getAddress().getAddress());
response = endpoint.renderByteArray(parameters, httpExchange.getRemoteAddress().getAddress().getAddress());
statusCode = 200;
}

Expand Down Expand Up @@ -138,6 +138,9 @@ private static void buildEndpointMap() {
map.put(SentinelController.pageEndpoint, SentinelController::page);
map.put(SentinelController.updateEndpoint, SentinelController::update);
} else if (runMode == RunMode.MicropayServer) {
// Add the ping endpoint. Add this before the dynamic pages to allow dynamic override.
map.put(MicropayController.serverPingEndpoint, MicropayController::serverPingPage);

// The Micropay controller builds its map dynamically based on the contents of a directory.
map.putAll(MicropayController.buildEndpointMap());
} else if (runMode == RunMode.MicropayClient) {
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/co/nyzo/verifier/web/elements/Head.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

public class Head extends HtmlTag {

private static final String standardMetadata = "<meta name=\"format-detection\" content=\"telephone=no\" />" +
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\" />";

@Override
public String getName() {
return "head";
}

public void addStandardMetadata() {
addRaw(standardMetadata);
public Head addStandardMetadata() {
add(new Meta().attr("name", "format-detection").attr("content", "telephone=no"));
add(new Meta().attr("name", "viewport")
.attr("content", "width=device-width, initial-scale=1, maximum-scale=1"));
return this;
}
}
3 changes: 1 addition & 2 deletions src/main/java/co/nyzo/verifier/web/elements/Html.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

public class Html extends HtmlTag {

private static final String docType = ("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " +
"\"http://www.w3.org/TR/html4/strict.dtd\">");
private static final String docType = ("<!doctype html>");

@Override
public String render() {
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/co/nyzo/verifier/web/elements/HtmlTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public abstract class HtmlTag implements HtmlElement {

private List<HtmlElement> elements = new ArrayList<>();
private Map<String, String> attributes = new HashMap<>();
private boolean includeClosingTag = true;

public abstract String getName();

Expand All @@ -27,6 +28,10 @@ public HtmlTag addRaw(String rawHtml) {
return this;
}

public void setIncludeClosingTag(boolean includeClosingTag) {
this.includeClosingTag = includeClosingTag;
}

@Override
public String render() {
StringBuilder result = new StringBuilder();
Expand All @@ -38,7 +43,9 @@ public String render() {
for (HtmlElement element : elements) {
result.append(element.render());
}
result.append("</").append(getName()).append(">");
if (includeClosingTag) {
result.append("</").append(getName()).append(">");
}

return result.toString();
}
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/co/nyzo/verifier/web/elements/Meta.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package co.nyzo.verifier.web.elements;

public class Meta extends HtmlTag {

public Meta() {
setIncludeClosingTag(false);
}

@Override
public String getName() {
return "meta";
}
}

0 comments on commit cdab238

Please sign in to comment.