Skip to content

Commit c96ee6e

Browse files
committed
Add ConvexDirect API class for testing / local usage
1 parent 2459826 commit c96ee6e

File tree

7 files changed

+224
-43
lines changed

7 files changed

+224
-43
lines changed

convex-core/src/main/java/convex/core/cpos/BeliefMerge.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ Index<AccountKey, SignedData<Order>> vote( final Index<AccountKey, SignedData<Or
207207
// winning chain should have same consensus as my initial chain
208208
Order winningOrder = myOrder.withBlocks(winningBlocks);
209209

210-
final Order consensusOrder = updateConsensus(winningOrder,stakedOrders, totalStake);
210+
Order consensusOrder = updateConsensus(winningOrder,stakedOrders, totalStake);
211211

212212
Index<AccountKey, SignedData<Order>> resultOrders = filteredOrders;
213213
if (!consensusOrder.consensusEquals(myOrder)) {

convex-core/src/main/java/convex/core/cvm/Peer.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@
2525
import convex.core.data.Maps;
2626
import convex.core.data.Ref;
2727
import convex.core.data.SignedData;
28+
import convex.core.data.Strings;
2829
import convex.core.data.Vectors;
2930
import convex.core.data.prim.CVMLong;
3031
import convex.core.exceptions.InvalidDataException;
3132
import convex.core.init.Init;
33+
import convex.core.lang.RT;
3234
import convex.core.store.AStore;
3335
import convex.core.store.Stores;
3436
import convex.core.util.Utils;
@@ -608,6 +610,45 @@ public Peer proposeBlock(Block block) {
608610
// result=result.updateState();
609611
return result;
610612
}
613+
614+
public Result checkTransaction(SignedData<ATransaction> sd) {
615+
616+
// TODO: throttle?
617+
ATransaction tx=RT.ensureTransaction(sd.getValue());
618+
619+
// System.out.println("transact: "+v);
620+
if (tx==null) {
621+
return Result.error(ErrorCodes.FORMAT,Strings.BAD_FORMAT);
622+
}
623+
624+
State s=getConsensusState();
625+
AccountStatus as=s.getAccount(tx.getOrigin());
626+
if (as==null) {
627+
return Result.error(ErrorCodes.NOBODY, Strings.NO_SUCH_ACCOUNT);
628+
}
629+
630+
if (tx.getSequence()<=as.getSequence()) {
631+
return Result.error(ErrorCodes.SEQUENCE, Strings.OLD_SEQUENCE);
632+
}
633+
634+
AccountKey expectedKey=as.getAccountKey();
635+
if (expectedKey==null) {
636+
return Result.error(ErrorCodes.STATE, Strings.NO_TX_FOR_ACTOR);
637+
}
638+
639+
AccountKey pubKey=sd.getAccountKey();
640+
if (!expectedKey.equals(pubKey)) {
641+
return Result.error(ErrorCodes.SIGNATURE, Strings.WRONG_KEY );
642+
}
643+
644+
if (!sd.checkSignature()) {
645+
// SECURITY: Client tried to send a badly signed transaction!
646+
return Result.error(ErrorCodes.SIGNATURE, Strings.BAD_SIGNATURE);
647+
}
648+
649+
// All checks passed OK!
650+
return null;
651+
}
611652

612653
/**
613654
* Gets the Final Point for this Peer

convex-core/src/main/java/convex/core/init/Init.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package convex.core.init;
22

33
import java.io.IOException;
4-
import java.util.ArrayList;
54
import java.util.List;
65

76
import convex.core.Coin;
@@ -391,7 +390,7 @@ private static State addStandardLibraries(State s) {
391390
* @param peerKeys
392391
* @return
393392
*/
394-
public static State createTestState(ArrayList<AccountKey> peerKeys) {
393+
public static State createTestState(List<AccountKey> peerKeys) {
395394
State s=createState(peerKeys);
396395
s = doActorDeploy(s, "/convex/asset/nft/tokens.cvx");
397396
s = doActorDeploy(s, "/convex/lab/play.cvx");

convex-peer/src/main/java/convex/api/Convex.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import convex.core.store.Stores;
4848
import convex.core.util.Utils;
4949
import convex.net.IPUtils;
50-
import convex.net.ResultConsumer;
5150
import convex.peer.Config;
5251
import convex.peer.Server;
5352

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package convex.api;
2+
3+
import java.io.IOException;
4+
import java.net.InetSocketAddress;
5+
import java.util.concurrent.CompletableFuture;
6+
import java.util.concurrent.TimeoutException;
7+
8+
import convex.core.Result;
9+
import convex.core.ResultContext;
10+
import convex.core.cpos.Block;
11+
import convex.core.crypto.AKeyPair;
12+
import convex.core.cvm.Address;
13+
import convex.core.cvm.Peer;
14+
import convex.core.cvm.PeerStatus;
15+
import convex.core.cvm.State;
16+
import convex.core.cvm.transactions.ATransaction;
17+
import convex.core.data.ACell;
18+
import convex.core.data.AccountKey;
19+
import convex.core.data.Blob;
20+
import convex.core.data.Hash;
21+
import convex.core.data.SignedData;
22+
import convex.core.data.prim.CVMLong;
23+
import convex.core.message.Message;
24+
import convex.core.store.AStore;
25+
import convex.core.util.Utils;
26+
27+
/**
28+
* Convex API instance that directly interacts with a Peer instance
29+
*/
30+
public class ConvexDirect extends Convex {
31+
32+
protected Peer peer;
33+
private boolean isConnected=true;
34+
35+
protected ConvexDirect(Address address, AKeyPair keyPair, Peer initial) {
36+
super(address, keyPair);
37+
this.peer=initial;
38+
}
39+
40+
public static ConvexDirect create(AKeyPair peerKey,State state) {
41+
AccountKey key=peerKey.getAccountKey();
42+
PeerStatus ps= state.getPeer(key);
43+
if (ps==null) throw new IllegalStateException("Peer does not exist in desired state");
44+
Address cont=ps.getController();
45+
return new ConvexDirect(cont,peerKey,Peer.create(peerKey, state));
46+
}
47+
48+
@Override
49+
public boolean isConnected() {
50+
return isConnected;
51+
}
52+
53+
@Override
54+
public synchronized CompletableFuture<Result> transact(SignedData<ATransaction> signedTransaction) {
55+
try {
56+
CVMLong id=CVMLong.create(getNextID());
57+
Peer p=peer;
58+
Result failure=p.checkTransaction(signedTransaction);
59+
if (failure!=null) {
60+
return CompletableFuture.completedFuture(failure.withID(id));
61+
}
62+
63+
long ts=Utils.getCurrentTimestamp();
64+
Block block=Block.of(ts, signedTransaction);
65+
66+
// Peer updates
67+
p=p.updateTimestamp(ts);
68+
p=p.proposeBlock(block);
69+
p=p.mergeBeliefs();
70+
p=p.updateState();
71+
long blockNum=p.getPeerOrder().count()-1;
72+
peer=p;
73+
74+
Result result= p.getResult(blockNum, 0);
75+
return CompletableFuture.completedFuture(result.withID(id));
76+
} catch (Exception e) {
77+
return CompletableFuture.completedFuture(Result.fromException(e));
78+
}
79+
}
80+
81+
@Override
82+
public CompletableFuture<Result> messageRaw(Blob message) {
83+
// TODO Auto-generated method stub
84+
return null;
85+
}
86+
87+
@Override
88+
public CompletableFuture<Result> message(Message message) {
89+
// TODO Auto-generated method stub
90+
return null;
91+
}
92+
93+
@Override
94+
public <T extends ACell> CompletableFuture<T> acquire(Hash hash, AStore store) {
95+
// TODO Auto-generated method stub
96+
return null;
97+
}
98+
99+
@Override
100+
public CompletableFuture<Result> requestStatus() {
101+
// TODO Auto-generated method stub
102+
return null;
103+
}
104+
105+
@Override
106+
public CompletableFuture<Result> requestChallenge(SignedData<ACell> data) {
107+
// TODO Auto-generated method stub
108+
return null;
109+
}
110+
111+
@Override
112+
public CompletableFuture<Result> query(ACell query, Address address) {
113+
CVMLong id=CVMLong.create(getNextID());
114+
ResultContext rc= peer.executeQuery(query, address);
115+
return CompletableFuture.completedFuture(Result.fromContext(id,rc));
116+
}
117+
118+
@Override
119+
public void close() {
120+
peer=null;
121+
}
122+
123+
@Override
124+
public String toString() {
125+
return "Direct client with peer state: "+peer.getConsensusState().getHash();
126+
}
127+
128+
@Override
129+
public InetSocketAddress getHostAddress() {
130+
return null;
131+
}
132+
133+
@Override
134+
public void reconnect() throws IOException, TimeoutException, InterruptedException {
135+
isConnected=true;
136+
}
137+
138+
139+
140+
}

convex-peer/src/main/java/convex/peer/TransactionHandler.java

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import convex.core.data.prim.CVMLong;
3939
import convex.core.exceptions.BadFormatException;
4040
import convex.core.exceptions.MissingDataException;
41-
import convex.core.lang.RT;
4241
import convex.core.lang.Reader;
4342
import convex.core.message.Message;
4443
import convex.core.util.LoadMonitor;
@@ -156,7 +155,7 @@ protected void processMessage(Message m) throws InterruptedException {
156155
SignedData<ATransaction> sd = (SignedData<ATransaction>) v.get(2);
157156

158157
// Check our transaction is valid and we want to process it
159-
Result error=checkTransaction(sd);
158+
Result error=server.getPeer().checkTransaction(sd);
160159
if (error!=null) {
161160
m.returnResult(error.withSource(SourceCodes.PEER));
162161
return;
@@ -179,44 +178,7 @@ protected void processMessage(Message m) throws InterruptedException {
179178
}
180179
}
181180

182-
private Result checkTransaction(SignedData<ATransaction> sd) {
183181

184-
// TODO: throttle?
185-
ATransaction tx=RT.ensureTransaction(sd.getValue());
186-
187-
// System.out.println("transact: "+v);
188-
if (tx==null) {
189-
return Result.error(ErrorCodes.FORMAT,Strings.BAD_FORMAT);
190-
}
191-
192-
State s=server.getPeer().getConsensusState();
193-
AccountStatus as=s.getAccount(tx.getOrigin());
194-
if (as==null) {
195-
return Result.error(ErrorCodes.NOBODY, Strings.NO_SUCH_ACCOUNT);
196-
}
197-
198-
if (tx.getSequence()<=as.getSequence()) {
199-
return Result.error(ErrorCodes.SEQUENCE, Strings.OLD_SEQUENCE);
200-
}
201-
202-
AccountKey expectedKey=as.getAccountKey();
203-
if (expectedKey==null) {
204-
return Result.error(ErrorCodes.STATE, Strings.NO_TX_FOR_ACTOR);
205-
}
206-
207-
AccountKey pubKey=sd.getAccountKey();
208-
if (!expectedKey.equals(pubKey)) {
209-
return Result.error(ErrorCodes.SIGNATURE, Strings.WRONG_KEY );
210-
}
211-
212-
if (!sd.checkSignature()) {
213-
// SECURITY: Client tried to send a badly signed transaction!
214-
return Result.error(ErrorCodes.SIGNATURE, Strings.BAD_SIGNATURE);
215-
}
216-
217-
// All checks passed OK!
218-
return null;
219-
}
220182

221183
/**
222184
* Sets a request observer, which will be called whenever the Peer
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package convex.api;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import java.util.List;
8+
9+
import org.junit.jupiter.api.Test;
10+
11+
import convex.core.Result;
12+
import convex.core.crypto.AKeyPair;
13+
import convex.core.cvm.Address;
14+
import convex.core.cvm.State;
15+
import convex.core.data.prim.CVMLong;
16+
import convex.core.init.Init;
17+
import convex.core.init.InitTest;
18+
import convex.core.lang.ACVMTest;
19+
20+
/**
21+
* Tests for Convex Direct client
22+
*/
23+
public class ConvexDirectTest extends ACVMTest {
24+
static final AKeyPair peerKey=AKeyPair.createSeeded(5675675);
25+
26+
@Test public void testSetup() throws InterruptedException {
27+
State state=Init.createTestState(List.of(peerKey.getAccountKey()));
28+
ConvexDirect convex=ConvexDirect.create(peerKey,state);
29+
Address addr=convex.getAddress();
30+
31+
assertTrue(convex.isConnected());
32+
assertEquals(InitTest.FIRST_PEER_ADDRESS,addr);
33+
34+
assertEquals(addr,convex.query("*address*").join().getValue());
35+
36+
Result r=convex.transactSync("(+ 1 2)");
37+
assertFalse(r.isError(),()->"Expected ed error: "+r);
38+
assertEquals(CVMLong.create(3),r.getValue());
39+
}
40+
}

0 commit comments

Comments
 (0)