diff --git a/ledger/execution/regular_tx_execution_test.go b/ledger/execution/regular_tx_execution_test.go index e5210ca7..cf1c9f54 100644 --- a/ledger/execution/regular_tx_execution_test.go +++ b/ledger/execution/regular_tx_execution_test.go @@ -1915,6 +1915,87 @@ func TestSplitRuleSplitEmptyRule(t *testing.T) { assert.True(et.state().Delivered().GetAccount(alice.Address).ReservedFunds[0].UsedFund.IsPositive()) } +func TestSplitRuleSplitZeroPayment(t *testing.T) { + assert := assert.New(t) + et, resourceID, alice, bob, carol, aliceInitBalance, bobInitBalance, carolInitBalance := setupForServicePayment(assert) + log.Infof("Bob's initial balance: %v", bobInitBalance) + log.Infof("Carol's initial balance: %v", carolInitBalance) + + txFee := getMinimumTxFee() + + initiator := types.MakeAcc("User David") + initiator.Balance = types.Coins{TFuelWei: big.NewInt(10000 * txFee), ThetaWei: big.NewInt(0)} + et.acc2State(initiator) + + splitAlice := types.Split{ + Address: alice.Address, + Percentage: 10, + } + + splitBob := types.Split{ + Address: bob.Address, + Percentage: 20, + } + + splitRuleTx := &types.SplitRuleTx{ + Fee: types.NewCoins(0, txFee), + ResourceID: resourceID, + Initiator: types.TxInput{ + Address: initiator.Address, + Sequence: 1, + }, + Splits: []types.Split{splitAlice, splitBob}, + Duration: uint64(99999), + } + signBytes := splitRuleTx.SignBytes(et.chainID) + splitRuleTx.Initiator.Signature = initiator.Sign(signBytes) + + res := et.executor.getTxExecutor(splitRuleTx).sanityCheck(et.chainID, et.state().Delivered(), splitRuleTx) + assert.True(res.IsOK(), res.Message) + _, res = et.executor.getTxExecutor(splitRuleTx).process(et.chainID, et.state().Delivered(), splitRuleTx) + assert.True(res.IsOK(), res.Message) + + // Simulate micropayment #1 between Alice and Bob, Carol should get a cut + payAmount := int64(0 * txFee) + srcSeq, tgtSeq, paymentSeq, reserveSeq := 1, 1, 1, 1 + + // Alice send the service payment to Carol, whose address is included in the split address list + _ = createServicePaymentTx(et.chainID, &alice, &carol, 0, srcSeq, tgtSeq, paymentSeq, reserveSeq, resourceID) + _ = createServicePaymentTx(et.chainID, &alice, &carol, 0, srcSeq, tgtSeq, paymentSeq, reserveSeq, resourceID) + servicePaymentTx := createServicePaymentTx(et.chainID, &alice, &carol, payAmount, srcSeq, tgtSeq, paymentSeq, reserveSeq, resourceID) + res = et.executor.getTxExecutor(servicePaymentTx).sanityCheck(et.chainID, et.state().Delivered(), servicePaymentTx) + assert.True(res.IsOK(), res.Message) + + assert.Equal(0, len(et.state().Delivered().GetSlashIntents())) + _, res = et.executor.getTxExecutor(servicePaymentTx).process(et.chainID, et.state().Delivered(), servicePaymentTx) + assert.True(res.IsOK(), res.Message) + + et.state().Commit() + + aliceFinalBalance := et.state().Delivered().GetAccount(alice.Address).Balance + bobFinalBalance := et.state().Delivered().GetAccount(bob.Address).Balance + carolFinalBalance := et.state().Delivered().GetAccount(carol.Address).Balance + log.Infof("Bob's final balance: %v", bobFinalBalance) + log.Infof("Carol's final balance: %v", carolFinalBalance) + + // Check the balances of the relevant accounts + aliceSplitCoins := types.Coins{TFuelWei: big.NewInt(0), ThetaWei: big.NewInt(0)} // zero payment + bobSplitCoins := types.Coins{TFuelWei: big.NewInt(0), ThetaWei: big.NewInt(0)} // zero payment + carolSplitCoins := types.Coins{TFuelWei: big.NewInt(0), ThetaWei: big.NewInt(0)} // zero payment + aliceReservedFund := types.Coins{TFuelWei: big.NewInt(2001 * txFee), ThetaWei: big.NewInt(0)} + reserveFundTxFee := types.NewCoins(0, getMinimumTxFee()) + servicePaymentTxFee := types.NewCoins(0, txFee) + + assert.Equal(aliceInitBalance.Minus(aliceReservedFund).Minus(reserveFundTxFee).Plus(aliceSplitCoins), aliceFinalBalance) + assert.Equal(bobInitBalance.Plus(bobSplitCoins), bobFinalBalance) + assert.Equal(carolInitBalance.Plus(carolSplitCoins).Minus(servicePaymentTxFee), carolFinalBalance) + assert.Equal(uint64(1), et.state().Delivered().GetAccount(alice.Address).Sequence) // seq=1 due to reserveFundTx + assert.Equal(uint64(0), et.state().Delivered().GetAccount(bob.Address).Sequence) + assert.Equal(uint64(0), et.state().Delivered().GetAccount(carol.Address).Sequence) // target's seq should not increase after servicePaymentTx + assert.Equal(uint64(1), et.state().Delivered().GetAccount(initiator.Address).Sequence) // seq=1 due to splitRuleTx + assert.Equal(1, len(et.state().Delivered().GetAccount(alice.Address).ReservedFunds)) + assert.True(et.state().Delivered().GetAccount(alice.Address).ReservedFunds[0].UsedFund.IsZero()) +} func TestSplitRuleTxSplitPaymentRounding(t *testing.T) { assert := assert.New(t) et, resourceID, alice, bob, carol, aliceInitBalance, bobInitBalance, carolInitBalance := setupForServicePayment(assert)