Skip to content

Commit 4ac582e

Browse files
authored
Merge pull request #1230 from oasisprotocol/ptrus/bugfix/numeric-to-big-int
common: Fix NumericToBigInt returning zero for negative exponents
2 parents 6ccc871 + ba6d086 commit 4ac582e

File tree

5 files changed

+65
-3
lines changed

5 files changed

+65
-3
lines changed

.changelog/1230.bugfix.1.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
analyzer/runtime: Fix pointer comparison in balance update check
2+
3+
The condition `change != big.NewInt(0)` was comparing pointers instead
4+
of values, causing it to always be true. Changed to `change.Sign() != 0`
5+
for proper value comparison.

.changelog/1230.bugfix.2.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
common: Fix NumericToBigInt returning zero for negative exponents
2+
3+
The function was returning `*big0` instead of `*bi` for negative
4+
exponents, causing it to always return zero. Added tests for the
5+
function.

analyzer/runtime/runtime.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ func (m *processor) queueDbUpdates(batch *storage.QueryBatch, data *BlockData) {
617617
// Update EVM token balances (dead reckoning).
618618
for key, change := range data.TokenBalanceChanges {
619619
// Update (dead-reckon) the DB balance only if it's actually changed.
620-
if change != big.NewInt(0) && m.mode != analyzer.FastSyncMode {
620+
if change.Sign() != 0 && m.mode != analyzer.FastSyncMode {
621621
if key.TokenAddress == evm.NativeRuntimeTokenAddress {
622622
batch.Queue(queries.RuntimeNativeBalanceUpsert, m.runtime, key.AccountAddress, nativeTokenSymbol(m.sdkPT), change.String())
623623
} else {

common/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ func NumericToBigInt(n pgtype.Numeric) (BigInt, error) {
168168
remainder := &big.Int{}
169169
bi.DivMod(bi, div, remainder)
170170
if remainder.Cmp(big0) != 0 {
171-
return BigInt{Int: *big0}, fmt.Errorf("cannot convert %v to integer", n)
171+
return BigInt{}, fmt.Errorf("cannot convert %v to integer", n)
172172
}
173-
return BigInt{Int: *big0}, nil
173+
return BigInt{Int: *bi}, nil
174174
}
175175

176176
// Decimal is a wrapper around apd.Decimal to allow for custom JSON marshaling.

common/types_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"encoding/json"
55
"fmt"
66
"math"
7+
"math/big"
78
"testing"
89

10+
"github.com/jackc/pgx/v5/pgtype"
911
"github.com/oasisprotocol/oasis-core/go/common/cbor"
1012
"github.com/stretchr/testify/require"
1113
)
@@ -122,3 +124,53 @@ func TestBigDecimalNumeric(t *testing.T) {
122124
require.EqualValues(t, dec, roundTripped, "BigDecimal should match after Numeric conversion for value %s", tc.value)
123125
}
124126
}
127+
128+
func TestNumericToBigInt(t *testing.T) {
129+
for _, tc := range []struct {
130+
name string
131+
numeric pgtype.Numeric
132+
expected int64
133+
hasError bool
134+
}{
135+
{
136+
name: "zero exponent",
137+
numeric: pgtype.Numeric{Int: big.NewInt(12345), Exp: 0, Valid: true},
138+
expected: 12345,
139+
},
140+
{
141+
name: "positive exponent",
142+
numeric: pgtype.Numeric{Int: big.NewInt(123), Exp: 2, Valid: true},
143+
expected: 12300,
144+
},
145+
{
146+
name: "negative exponent exact division",
147+
numeric: pgtype.Numeric{Int: big.NewInt(12300), Exp: -2, Valid: true},
148+
expected: 123,
149+
},
150+
{
151+
name: "negative exponent with remainder",
152+
numeric: pgtype.Numeric{Int: big.NewInt(12345), Exp: -2, Valid: true},
153+
hasError: true,
154+
},
155+
{
156+
name: "zero value",
157+
numeric: pgtype.Numeric{Int: big.NewInt(0), Exp: 0, Valid: true},
158+
expected: 0,
159+
},
160+
{
161+
name: "negative value",
162+
numeric: pgtype.Numeric{Int: big.NewInt(-500), Exp: 1, Valid: true},
163+
expected: -5000,
164+
},
165+
} {
166+
t.Run(tc.name, func(t *testing.T) {
167+
result, err := NumericToBigInt(tc.numeric)
168+
if tc.hasError {
169+
require.Error(t, err)
170+
} else {
171+
require.NoError(t, err)
172+
require.Equal(t, tc.expected, result.Int64())
173+
}
174+
})
175+
}
176+
}

0 commit comments

Comments
 (0)