From 3288dab14e1c5f4ab17137cf3a6bff9b19f1a7f8 Mon Sep 17 00:00:00 2001 From: mikera Date: Fri, 4 Oct 2024 11:42:00 +0100 Subject: [PATCH] Tests and fix for set-peer-stake --- .../java/convex/core/cpos/CPoSConstants.java | 10 +++- .../src/main/java/convex/core/cvm/State.java | 14 ++++- .../main/java/convex/core/lang/Context.java | 9 +--- .../main/java/convex/core/util/Economics.java | 3 +- .../test/java/convex/core/TokenomicsTest.java | 2 +- .../java/convex/core/TransactionTest.java | 5 +- .../test/java/convex/core/lang/CoreTest.java | 51 +++++++++++++++++++ 7 files changed, 80 insertions(+), 14 deletions(-) diff --git a/convex-core/src/main/java/convex/core/cpos/CPoSConstants.java b/convex-core/src/main/java/convex/core/cpos/CPoSConstants.java index 6498a9c90..e73bd8463 100644 --- a/convex-core/src/main/java/convex/core/cpos/CPoSConstants.java +++ b/convex-core/src/main/java/convex/core/cpos/CPoSConstants.java @@ -26,13 +26,21 @@ public class CPoSConstants { * Milliseconds before peer stake influence starts to decay (3 mins default) */ public static final double PEER_DECAY_DELAY = 3*60*1000; + /** - * Time for peer stake to decay by factor 1/e (5 mins default) + * Time for peer stake to decay by factor 1/e (30 mins default) */ public static final double PEER_DECAY_TIME = 5*60*1000; + + /** + * Minimum proportion of stake that a peer can decay to + */ + public static final double PEER_DECAY_MINIMUM = 0.001; + /** * Maximum time a block can be resurrected from the past (1 min) */ public static final long MAX_BLOCK_BACKDATE = 60*1000; + } diff --git a/convex-core/src/main/java/convex/core/cvm/State.java b/convex-core/src/main/java/convex/core/cvm/State.java index 23a95a22e..33f94ccdd 100644 --- a/convex-core/src/main/java/convex/core/cvm/State.java +++ b/convex-core/src/main/java/convex/core/cvm/State.java @@ -487,6 +487,7 @@ private BlockResult applyTransactions(Block block) throws InvalidBlockException State state = this; int blockLength = block.length(); Result[] results = new Result[blockLength]; + long fees=0L; AVector> transactions = block.getTransactions(); for (int i = 0; i < blockLength; i++) { @@ -501,6 +502,10 @@ private BlockResult applyTransactions(Block block) throws InvalidBlockException // record results from result context results[i] = Result.fromContext(CVMLong.create(i),rc); + // Get fees from ResultContext + // NOTE: Juice fees includes transaction overhead fees + fees+=rc.getJuiceFees(); + // state update state = rc.context.getState(); //} catch (Exception e) { @@ -509,8 +514,15 @@ private BlockResult applyTransactions(Block block) throws InvalidBlockException // log.error(msg,e); //} } + + // maybe add used juice to peer fees + if (fees>0L) { + long oldFees=state.getGlobalFees().longValue(); + long newFees=oldFees+fees; + state=state.withGlobalFees(CVMLong.create(newFees)); + } - // TODO: changes for complete block? + // TODO: other things for complete block? return BlockResult.create(state, results); } diff --git a/convex-core/src/main/java/convex/core/lang/Context.java b/convex-core/src/main/java/convex/core/lang/Context.java index 5ec3410ae..49378b5ef 100644 --- a/convex-core/src/main/java/convex/core/lang/Context.java +++ b/convex-core/src/main/java/convex/core/lang/Context.java @@ -411,13 +411,6 @@ public Context completeTransaction(State initialState, ResultContext rc) { // update Account state=state.putAccount(address,account); - // maybe add used juice to peer fees - if (juiceFees>0L) { - long oldFees=state.getGlobalFees().longValue(); - long newFees=oldFees+juiceFees; - state=state.withGlobalFees(CVMLong.create(newFees)); - } - // final state update and result reporting Context rctx=this.withState(state); if (juiceFailure) { @@ -2007,7 +2000,7 @@ public Context setDelegatedStake(AccountKey peerKey, Address staker, long newSta * @return Updated Context */ public Context setPeerStake(AccountKey peerKey, long newStake) { - return setPeerStake(peerKey,newStake); + return setPeerStake(peerKey,getAddress(),newStake); } /** diff --git a/convex-core/src/main/java/convex/core/util/Economics.java b/convex-core/src/main/java/convex/core/util/Economics.java index 9ab1eb23d..b20e1a0ea 100644 --- a/convex-core/src/main/java/convex/core/util/Economics.java +++ b/convex-core/src/main/java/convex/core/util/Economics.java @@ -50,11 +50,12 @@ public static long swapPrice(long delta,long a, long b) { } public static double stakeDecay(long time, long peerTime) { + if (peerTime<0) return CPoSConstants.PEER_DECAY_MINIMUM; if (peerTime>=time) return 1.0; double delay=time-peerTime; delay-=CPoSConstants.PEER_DECAY_DELAY; if (delay<0) return 1.0; - return Math.max(0.001, Math.exp(-delay/CPoSConstants.PEER_DECAY_TIME)); + return Math.max(CPoSConstants.PEER_DECAY_MINIMUM, Math.exp(-delay/CPoSConstants.PEER_DECAY_TIME)); } } diff --git a/convex-core/src/test/java/convex/core/TokenomicsTest.java b/convex-core/src/test/java/convex/core/TokenomicsTest.java index 21901fcad..2d18a9860 100644 --- a/convex-core/src/test/java/convex/core/TokenomicsTest.java +++ b/convex-core/src/test/java/convex/core/TokenomicsTest.java @@ -179,7 +179,7 @@ public void testTransferFail() { protected void checkFinalState(ResultContext rc, boolean memUsed) { // Nothing should have gone wrong with total coin supply - assertEquals(Coin.MAX_SUPPLY,rc.getState().computeTotalBalance()); + assertEquals(Coin.MAX_SUPPLY-rc.getJuiceFees(),rc.getState().computeTotalBalance()); if (memUsed) { // we expect total memory to have fallen because of memory used diff --git a/convex-core/src/test/java/convex/core/TransactionTest.java b/convex-core/src/test/java/convex/core/TransactionTest.java index c93bede8f..91df6f8de 100644 --- a/convex-core/src/test/java/convex/core/TransactionTest.java +++ b/convex-core/src/test/java/convex/core/TransactionTest.java @@ -72,9 +72,10 @@ public void testTransfer() { long memSize=Cells.storageSize(t1); - State s=apply(t1); + ResultContext rc=state().applyTransaction(t1); + State s=rc.context.getState(); long expectedFees=(Juice.TRANSACTION+Juice.TRANSFER+Juice.TRANSACTION_PER_BYTE*memSize)*JP; - assertEquals(expectedFees,s.getGlobalFees().longValue()); + assertEquals(expectedFees,rc.getJuiceFees()); long NBAL=s.getAccount(HERO).getBalance(); long balanceDrop=IBAL-NBAL; diff --git a/convex-core/src/test/java/convex/core/lang/CoreTest.java b/convex-core/src/test/java/convex/core/lang/CoreTest.java index 0ac514584..ac88d49d3 100644 --- a/convex-core/src/test/java/convex/core/lang/CoreTest.java +++ b/convex-core/src/test/java/convex/core/lang/CoreTest.java @@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.util.HashMap; import org.junit.jupiter.api.Test; @@ -36,6 +37,7 @@ import convex.core.ErrorCodes; import convex.core.cpos.Block; import convex.core.cpos.BlockResult; +import convex.core.cpos.CPoSConstants; import convex.core.crypto.AKeyPair; import convex.core.cvm.State; import convex.core.data.ABlob; @@ -57,6 +59,7 @@ import convex.core.data.Lists; import convex.core.data.MapEntry; import convex.core.data.Maps; +import convex.core.data.PeerStatus; import convex.core.data.Sets; import convex.core.data.SignedData; import convex.core.data.Strings; @@ -3380,6 +3383,54 @@ public void testStake() { assertArityError(step(ctx,"(stake my-peer 1000 :foo)")); } + @Test + public void testSetPeerStake() { + // Not a real peer key, but we don't care because not actually running one.... + AccountKey KEY=AccountKey.fromHex("1234567812345678123456781234567812345678123456781234567812345678"); + long STK=1000000; + Context ctx=context(); + + + assertNull(ctx.getState().getPeer(KEY)); + assertStateError(step(ctx,"(set-peer-stake "+KEY+" "+STK+")")); + + // create peer with initial stake + ctx=exec(ctx,"(create-peer "+KEY+" "+STK+")"); + + // Check stake has been established + PeerStatus ps=ctx.getState().getPeer(KEY); + assertEquals(ps, eval(ctx,"(get-in *state* [:peers "+KEY+"])")); + assertEquals(STK,ps.getPeerStake()); + assertEquals(STK,ps.getTotalStake()); + assertEquals(STK,ps.getBalance()); + + // Effective stake should be decayed to minimum, since no blocks for this peer yet + HashMap stks=ctx.getState().computeStakes(); + assertEquals(STK*CPoSConstants.PEER_DECAY_MINIMUM,stks.get(KEY)); + + // Increase stake + ctx=exec(ctx,"(set-peer-stake "+KEY+" "+STK*3+")"); + ps=ctx.getState().getPeer(KEY); + assertEquals(STK*3,ps.getPeerStake()); + assertEquals(STK*3,ps.getTotalStake()); + assertEquals(STK*3,ps.getBalance()); + + + assertFundsError(step(ctx,"(set-peer-stake "+KEY+" 999999999999999999)")); + assertEquals(Coin.MAX_SUPPLY,ctx.getState().computeTotalBalance()); + + // Finally remove all stake + ctx=exec(ctx,"(set-peer-stake "+KEY+" 0)"); + ps=ctx.getState().getPeer(KEY); + assertEquals(0,ps.getPeerStake()); + assertEquals(0,ps.getTotalStake()); + assertEquals(0,ps.getBalance()); + + assertArityError(step(ctx,"(set-peer-stake)")); + assertArityError(step(ctx,"(set-peer-stake "+KEY+")")); + assertArityError(step(ctx,"(set-peer-stake "+KEY+" :foo :bar)")); + } + @Test public void testSetPeerData() { String newHostname = "new_hostname:1234";