Skip to content

Commit

Permalink
fixed edge cases about balance, neg and zero
Browse files Browse the repository at this point in the history
  • Loading branch information
ascandone committed Aug 23, 2024
1 parent 8f5df95 commit 554a868
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 12 deletions.
21 changes: 16 additions & 5 deletions interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -687,12 +687,16 @@ func (s *programState) receiveFrom(destination parser.Destination, amount *big.I
case *parser.DestinationTo:
var remainingAmount big.Int
remainingAmount.Sub(&amountToReceive, receivedTotal)
// receivedTotal += destination.receive(monetary-receivedTotal, ctx)
received, err := s.receiveFrom(destinationTarget.Destination, &remainingAmount)
if err != nil {
return err

if remainingAmount.Cmp(big.NewInt(0)) != 0 {
// receivedTotal += destination.receive(monetary-receivedTotal, ctx)
received, err := s.receiveFrom(destinationTarget.Destination, &remainingAmount)
if err != nil {
return err
}
receivedTotal.Add(receivedTotal, received)
}
receivedTotal.Add(receivedTotal, received)

return nil

default:
Expand Down Expand Up @@ -815,6 +819,13 @@ func balance(

// body
balance := s.getBalance(*account, *asset)
if balance.Cmp(big.NewInt(0)) == -1 {
return nil, NegativeBalanceError{
Account: *account,
Amount: *balance,
}
}

var balanceCopy big.Int
balanceCopy.Set(balance)

Expand Down
9 changes: 9 additions & 0 deletions interpreter/interpreter_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ func (e InvalidTypeErr) Error() string {
return fmt.Sprintf("This type does not exist: %s", e.Name)
}

type NegativeBalanceError struct {
Account string
Amount big.Int
}

func (e NegativeBalanceError) Error() string {
return fmt.Sprintf("Cannot fetch negative balance from account @%s", e.Account)
}

type NegativeAmountErr struct{ Amount MonetaryInt }

func (e NegativeAmountErr) Error() string {
Expand Down
76 changes: 73 additions & 3 deletions interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,27 @@ func TestDestinationComplex(t *testing.T) {

// TODO TestNeededBalances, TestSetTxMeta, TestSetAccountMeta

func TestSendZero(t *testing.T) {
tc := NewTestCase()
tc.compile(t, `
send [COIN 0] (
source = @src
destination = @dest
)`)
tc.expected = CaseResult{
Postings: []Posting{
{
Asset: "COIN",
Amount: big.NewInt(0),
Source: "src",
Destination: "dest",
},
},
Error: nil,
}
test(t, tc)
}

func TestBalance(t *testing.T) {
tc := NewTestCase()
tc.compile(t, `
Expand All @@ -1485,6 +1506,52 @@ func TestBalance(t *testing.T) {
test(t, tc)
}

func TestNegativeBalance(t *testing.T) {
tc := NewTestCase()
tc.compile(t, `
vars {
monetary $balance = balance(@a, EUR/2)
}
send $balance (
source = @world
destination = @dest
)`)
tc.setBalance("a", "EUR/2", -100)
tc.expected = CaseResult{
Error: machine.NegativeBalanceError{
Account: "a",
Amount: *big.NewInt(-100),
},
}
test(t, tc)
}

func TestBalanceNotFound(t *testing.T) {
tc := NewTestCase()
tc.compile(t, `
vars {
monetary $balance = balance(@a, EUR/2)
}
send $balance (
source = @world
destination = @dest
)`)
tc.expected = CaseResult{
Postings: []Posting{
{
Asset: "EUR/2",
Amount: big.NewInt(0),
Source: "world",
Destination: "dest",
},
},
Error: nil,
}
test(t, tc)
}

func TestInoderDestination(t *testing.T) {
tc := NewTestCase()
tc.compile(t, `send [COIN 100] (
Expand Down Expand Up @@ -1695,16 +1762,19 @@ func TestVariableBalance(t *testing.T) {
tc := NewTestCase()
script = `
vars {
monetary $amount = balance(@world, USD/2)
monetary $amount = balance(@src, USD/2)
}
send $amount (
source = @A
destination = @B
)`
tc.compile(t, script)
tc.setBalance("world", "USD/2", -40)
tc.setBalance("src", "USD/2", -40)
tc.expected = CaseResult{
Error: machine.NegativeAmountErr{Amount: machine.NewMonetaryInt(-40)},
Error: machine.NegativeBalanceError{
Account: "src",
Amount: *big.NewInt(-40),
},
}
test(t, tc)
})
Expand Down
4 changes: 0 additions & 4 deletions interpreter/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,6 @@ func Reconcile(asset string, senders []Sender, receivers []Receiver) ([]Posting,
postingAmount = *receiver.Monetary
}

if postingAmt := big.Int(postingAmount); postingAmt.BitLen() == 0 {
continue
}

var postingToMerge *Posting
if len(postings) != 0 {
posting := &postings[len(postings)-1]
Expand Down
9 changes: 9 additions & 0 deletions interpreter/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ func TestReconcileSingletonExactMatch(t *testing.T) {
})
}

func TestReconcileZero(t *testing.T) {
runReconcileTestCase(t, ReconcileTestCase{
Currency: "COIN",
Senders: []Sender{{"src", big.NewInt(0)}},
Receivers: []Receiver{{"dest", big.NewInt(0)}},
Expected: []Posting{{"src", "dest", big.NewInt(0), "COIN"}},
})
}

func TestNoReceiversLeft(t *testing.T) {
runReconcileTestCase(t, ReconcileTestCase{
Senders: []Sender{{
Expand Down

0 comments on commit 554a868

Please sign in to comment.