Skip to content

Commit

Permalink
XBR Fix (crossbario#500)
Browse files Browse the repository at this point in the history
* fix XBR seller

* fix buyer
  • Loading branch information
om26er authored Sep 5, 2020
1 parent b22d294 commit 882450b
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
import java.util.concurrent.CompletableFuture;

import io.crossbar.autobahn.utils.AuthUtil;
import io.crossbar.autobahn.utils.Pair;
import io.crossbar.autobahn.wamp.Session;
import io.crossbar.autobahn.wamp.interfaces.IAuthenticator;
import io.crossbar.autobahn.wamp.types.Challenge;
import io.crossbar.autobahn.wamp.types.ChallengeResponse;
import io.crossbar.autobahn.utils.Pair;

import static io.crossbar.autobahn.wamp.utils.Shortcuts.getOrDefault;
import static org.libsodium.jni.SodiumConstants.SECRETKEY_BYTES;

public class CryptosignAuth implements IAuthenticator {
Expand All @@ -38,6 +37,15 @@ public static Pair<String, String> generateSigningKeyPair() {
return new Pair<>(publicKey, privateKey);
}

public CryptosignAuth(String authid, String privateKey) {
this(authid, privateKey, getPublicKey(AuthUtil.toBinary(privateKey)));
}

private static String getPublicKey(byte[] privateKeyRaw) {
SigningKey signingKey = new SigningKey(privateKeyRaw);
return AuthUtil.toHexString(signingKey.getVerifyKey().toBytes());
}

public CryptosignAuth(String authid, String privkey, Map<String, Object> authextra) {
this(authid, null, privkey, authextra);
}
Expand All @@ -64,9 +72,6 @@ public CryptosignAuth(String authid, String authrole, String privkey,
Map<String, Object> authextra) {
this.authid = authid;
this.authrole = authrole;
if (authextra == null || getOrDefault(authextra, "pubkey", null) == null) {
throw new RuntimeException("authextra must contain pubkey");
}
this.authextra = authextra;
try {
privateKeyRaw = AuthUtil.toBinary(privkey);
Expand Down
151 changes: 88 additions & 63 deletions autobahn/src/main/java/xbr/network/SimpleBuyer.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@
import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import io.crossbar.autobahn.wamp.Session;
Expand All @@ -53,6 +52,7 @@ public class SimpleBuyer {

private BigInteger mRemainingBalance;
private HashMap<String, Object> mChannel;
private Map<String, Object> mMakerConfig;

private final byte[] mPrivateKey;
private final byte[] mPublicKey;
Expand Down Expand Up @@ -86,24 +86,23 @@ public CompletableFuture<BigInteger> start(Session session, String consumerID) {
mSession = session;
mRunning = true;

List<Object> args = new ArrayList<>();
args.add(mEthAddr);
CompletableFuture<HashMap<String, Object>> payChannelF = mSession.call(
"xbr.marketmaker.get_active_payment_channel", args,
new TypeReference<HashMap<String, Object>>() {});
payChannelF.whenComplete((channel, throwable) -> {
if (throwable != null) {
future.completeExceptionally(throwable);
} else {
mChannel = channel;
balance().whenComplete((balance, throwable1) -> {
if (throwable1 != null) {
future.completeExceptionally(throwable1);
} else {
future.complete((BigInteger) balance.get("remaining"));
}
});
}
mSession.call(
"xbr.marketmaker.get_config",
Map.class
).thenCompose(makerConfig -> {
mMakerConfig = makerConfig;
return mSession.call(
"xbr.marketmaker.get_active_payment_channel",
new TypeReference<HashMap<String, Object>>() {},
mEthAddr);
}).thenCompose(channel -> {
mChannel = channel;
return balance();
}).thenAccept(balance -> {
future.complete((BigInteger) balance.get("remaining"));
}).exceptionally(throwable -> {
future.completeExceptionally(throwable);
return null;
});
return future;
}
Expand All @@ -127,22 +126,21 @@ public CompletableFuture<HashMap<String, Object>> balance() {
return future;
}

CompletableFuture<HashMap<String, Object>> balanceFuture = mSession.call(
mSession.call(
"xbr.marketmaker.get_payment_channel_balance",
new TypeReference<HashMap<String, Object>>() {},
mChannel.get("channel"));
balanceFuture.whenComplete((paymentBalance, throwable) -> {
if (throwable != null) {
future.completeExceptionally(throwable);
} else {
mRemainingBalance = new BigInteger((byte[]) paymentBalance.get("remaining"));
HashMap<String, Object> res = new HashMap<>();
res.put("amount", paymentBalance.get("amount"));
res.put("remaining", mRemainingBalance);
res.put("inflight", paymentBalance.get("inflight"));
mSeq = (int) paymentBalance.get("seq");
future.complete(res);
}
mChannel.get("channel_oid")
).thenAccept(paymentBalance -> {
mRemainingBalance = new BigInteger((byte[]) paymentBalance.get("remaining"));
HashMap<String, Object> res = new HashMap<>();
res.put("amount", paymentBalance.get("amount"));
res.put("remaining", mRemainingBalance);
res.put("inflight", paymentBalance.get("inflight"));
mSeq = (int) paymentBalance.get("seq");
future.complete(res);
}).exceptionally(throwable -> {
future.completeExceptionally(throwable);
return null;
});

return future;
Expand All @@ -157,24 +155,25 @@ public CompletableFuture<HashMap<String, Object>> openChannel(byte[] buyerAddr,
return future;
}

CompletableFuture<HashMap<String, Object>> callFuture = mSession.call(
mSession.call(
"xbr.marketmaker.open_payment_channel",
new TypeReference<HashMap<String, Object>>() {},
buyerAddr,
mEthAddr,
amount,
new SecureRandom(new byte[64]));
callFuture.whenComplete((paymentChannel, throwable) -> {
if (throwable != null) {
future.completeExceptionally(throwable);
} else {
BigInteger remaining = new BigInteger((byte[]) paymentChannel.get("remaining"));
HashMap<String, Object> res = new HashMap<>();
res.put("amount", paymentChannel.get("amount"));
res.put("remaining", remaining);
res.put("inflight", paymentChannel.get("inflight"));
future.complete(res);
}
new SecureRandom(new byte[64])
).thenAccept(paymentChannel -> {

BigInteger remaining = new BigInteger((byte[]) paymentChannel.get("remaining"));
HashMap<String, Object> res = new HashMap<>();
res.put("amount", paymentChannel.get("amount"));
res.put("remaining", remaining);
res.put("inflight", paymentChannel.get("inflight"));
future.complete(res);

}).exceptionally(throwable -> {
future.completeExceptionally(throwable);
return null;
});


Expand All @@ -188,48 +187,71 @@ public void closeChannel() {
public CompletableFuture<Object> unwrap(byte[] keyID, String encSerializer, byte[] ciphertext) {
CompletableFuture<Object> future = new CompletableFuture<>();

byte[] channelAddr = (byte[]) mChannel.get("channel");
// FIXME::
int currentBlock = 1;
int verifyingChainId = (int) mMakerConfig.get("verifying_chain_id");
String verifyingContractAddress = (String) mMakerConfig.get("verifying_contract_adr");
byte[] channelOidRaw = (byte[]) mChannel.get("channel_oid");
String channelOidHex = Numeric.toHexString(channelOidRaw);
byte[] marketOidRaw = (byte[]) mChannel.get("market_oid");
String marketOidHex = Numeric.toHexString(marketOidRaw);

if (!mKeys.containsKey(keyID)) {
CompletableFuture<HashMap<String, Object>> quoteF = mSession.call(
mSession.call(
"xbr.marketmaker.get_quote",
new TypeReference<HashMap<String, Object>>() {}, keyID);
quoteF.whenComplete((quote, throwable) -> {
new TypeReference<HashMap<String, Object>>() {},
keyID
).thenAccept(quote -> {
BigInteger price = Util.toXBR((byte[]) quote.get("price"));
// If we have the balance to buy...
if (mRemainingBalance.compareTo(price) > 0) {
int channelSeq = mSeq + 1;
boolean isFinal = false;
BigInteger remainingPost = mRemainingBalance.subtract(price);
try {
byte[] signature = Util.signEIP712Data(mECKey, channelAddr, channelSeq,
mRemainingBalance.subtract(price), isFinal);
BigInteger remainingPost = mRemainingBalance.subtract(price);
buyKey(keyID, channelAddr, channelSeq, price, remainingPost, signature,
byte[] signature = Util.signEIP712Data(mECKey, verifyingChainId,
verifyingContractAddress, currentBlock, marketOidHex, channelOidHex,
channelSeq, remainingPost, isFinal);
buyKey(keyID, channelOidRaw, channelSeq, price, remainingPost, signature,
ciphertext, future);
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}
}).exceptionally(throwable -> {
future.completeExceptionally(throwable);
return null;
});
} else {
future.completeExceptionally(new ApplicationError("xbr.error.insufficient_balance"));
}
return future;
}

private void buyKey(byte[] keyID, byte[] channelAddr, int channelSeq, BigInteger price,
private void buyKey(byte[] keyID, byte[] channelOid, int channelSeq, BigInteger price,
BigInteger balance, byte[] signature, byte[] ciphertext,
CompletableFuture<Object> future) {
CompletableFuture<HashMap<String, Object>> keyF = mSession.call(
mSession.call(
"xbr.marketmaker.buy_key", new TypeReference<HashMap<String, Object>>() {},
mEthAddr, mPublicKey, keyID, channelAddr, channelSeq,
Numeric.toBytesPadded(price, 32), Numeric.toBytesPadded(balance, 32), signature);
keyF.whenComplete((receipt, throwable) -> {
mEthAddr, mPublicKey, keyID, channelOid, channelSeq,
Numeric.toBytesPadded(price, 32), Numeric.toBytesPadded(balance, 32), signature
).thenAccept(receipt -> {

// FIXME::
int currentBlock = 1;
int verifyingChainId = (int) mMakerConfig.get("verifying_chain_id");
String verifyingContractAddress = (String) mMakerConfig.get("verifying_contract_adr");
byte[] channelOidRaw = (byte[]) mChannel.get("channel_oid");
String channelOidHex = Numeric.toHexString(channelOidRaw);
byte[] marketOidRaw = (byte[]) mChannel.get("market_oid");
String marketOidHex = Numeric.toHexString(marketOidRaw);

int remoteSeq = (int) receipt.get("channel_seq");
byte[] remaining = Numeric.toBytesPadded(
new BigInteger((byte[]) receipt.get("remaining")), 32);
String signer = Util.recoverEIP712Signer(channelAddr, (int) receipt.get("channel_seq"),
byte[] remaining = (byte[]) receipt.get("remaining");
String signer = Util.recoverEIP712Signer(verifyingChainId, verifyingContractAddress,
currentBlock, marketOidHex, channelOidHex, (int) receipt.get("channel_seq"),
new BigInteger(remaining), false, (byte[]) receipt.get("signature"));

if (!signer.equals(Numeric.toHexString(mMarketMakerAddr))) {
System.out.println("Shit went south, I am out...");
mSession.leave();
Expand All @@ -248,6 +270,9 @@ private void buyKey(byte[] keyID, byte[] channelAddr, int channelSeq, BigInteger
future.completeExceptionally(e);
}
}
}).exceptionally(throwable -> {
throwable.printStackTrace();
return null;
});
}
}
71 changes: 37 additions & 34 deletions autobahn/src/main/java/xbr/network/SimpleSeller.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
import io.crossbar.autobahn.wamp.types.Registration;

public class SimpleSeller {

private static final String TAG = SimpleSeller.class.getName();

private static final int STATE_NONE = 0;
private static final int STATE_STARTING = 1;
private static final int STATE_STARTED = 2;
Expand All @@ -59,6 +62,7 @@ public class SimpleSeller {
private int mSeq;
private HashMap<String, Object> mChannel;
private HashMap<String, Object> mPayingBalance;
private Map<String, Object> mMakerConfig;

private SimpleSeller(byte[] marketMakerAddr, byte[] sellerKey) {
mState = STATE_NONE;
Expand Down Expand Up @@ -122,40 +126,36 @@ public CompletableFuture<BigInteger> start(Session session) {

String provider = Numeric.toHexStringWithPrefix(mECKey.getPublicKey());
String procedureSell = String.format("xbr.provider.%s.sell", provider);
mSession.register(procedureSell, this::sell).thenAccept(registration -> {
mSessionRegs.add(registration);
}).exceptionally(throwable -> {
future.completeExceptionally(throwable);
return null;
});

String procedureCloseChannel = String.format("xbr.provider.%s.close_channel", provider);
mSession.register(procedureCloseChannel, this::closeChannel).thenAccept(registration -> {
mSession.register(procedureSell, this::sell).thenCompose(registration -> {
mSessionRegs.add(registration);
return mSession.register(procedureCloseChannel, this::closeChannel);
}).thenCompose(registration -> {
mSessionRegs.add(registration);
}).exceptionally(throwable -> {
future.completeExceptionally(throwable);
return null;
});

for (KeySeries series: mKeys.values()) {
series.start();
}
for (KeySeries series: mKeys.values()) {
series.start();
}

return session.call("xbr.marketmaker.get_config", Map.class);

mSession.call(
"xbr.marketmaker.get_active_paying_channel",
new TypeReference<HashMap<String, Object>>() {},
mAddr
).thenCompose(channel -> {
}).thenCompose(makerConfig -> {

mMakerConfig = makerConfig;

return mSession.call(
"xbr.marketmaker.get_active_paying_channel",
new TypeReference<HashMap<String, Object>>() {},
mAddr);
}).thenCompose(channel -> {
mChannel = channel;
return mSession.call(
"xbr.marketmaker.get_paying_channel_balance",
new TypeReference<HashMap<String, Object>>() {},
channel.get("channel"));
channel.get("channel_oid"));
}).thenAccept(payingBalance -> {
mSeq = (int) payingBalance.get("seq");
mBalance = new BigInteger((byte[]) payingBalance.get("remaining"));
BigInteger bi = new BigInteger("10").pow(18);
System.out.println(mBalance.divide(bi));
mState = STATE_STARTED;
future.complete(mBalance);
}).exceptionally(throwable -> {
Expand All @@ -173,8 +173,8 @@ public InvocationResult sell(List<Object> args, Map<String, Object> kwargs,
byte[] buyerPubKey = (byte[]) args.get(1);
byte[] keyIDRaw = (byte[]) args.get(2);
String keyID = Numeric.toHexString(keyIDRaw);
byte[] channelAddrRaw = (byte[]) args.get(3);
String channelAddr = Numeric.toHexString(channelAddrRaw);
byte[] channelOidRaw = (byte[]) args.get(3);
String channelOid = Numeric.toHexString(channelOidRaw);
int channelSeq = (int) args.get(4);
byte[] amountRaw = (byte[]) args.get(5);
BigInteger amount = new BigInteger(amountRaw);
Expand All @@ -190,8 +190,15 @@ public InvocationResult sell(List<Object> args, Map<String, Object> kwargs,
throw new ApplicationError("crossbar.error.no_such_object");
}

String signerAddr = Util.recoverEIP712Signer(channelAddrRaw, channelSeq, balance, false,
signature);
// FIXME::
int currentBlock = 1;
int verifyingChainId = (int) mMakerConfig.get("verifying_chain_id");
String verifyingContractAddress = (String) mMakerConfig.get("verifying_contract_adr");
byte[] marketOidRaw = (byte[]) mChannel.get("market_oid");
String marketOid = Numeric.toHexString(marketOidRaw);

String signerAddr = Util.recoverEIP712Signer(verifyingChainId, verifyingContractAddress,
currentBlock, marketOid, channelOid, channelSeq, balance, false, signature);

if (!signerAddr.equals(marketMakerAddr)) {
throw new ApplicationError("xbr.error.invalid_signature");
Expand All @@ -213,13 +220,9 @@ public InvocationResult sell(List<Object> args, Map<String, Object> kwargs,
receipt.put("balance", mBalance.toByteArray());

try {
byte[] sellerSignature = Util.signEIP712Data(
mECKey,
(byte[]) mChannel.get("channel"),
mSeq,
mBalance,
false
);
byte[] sellerSignature = Util.signEIP712Data(mECKey, verifyingChainId,
verifyingContractAddress, currentBlock, marketOid, channelOid, mSeq,
mBalance, false);
receipt.put("signature", sellerSignature);
} catch (IOException | JSONException e) {
e.printStackTrace();
Expand Down
Loading

0 comments on commit 882450b

Please sign in to comment.