refactor(collections): add UintValueEncoder and use Uint for wei store#2595
refactor(collections): add UintValueEncoder and use Uint for wei store#2595expertdicer wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the weiStore balance tracking in the bank keeper to use sdkmath.Uint instead of sdkmath.Int, introducing a new UintValueEncoder in the x/collections module. It also removes the custom SignedIntValueEncoder from the eth package, standardizing on collections.IntValueEncoder. The review identified two issues: a potential nil pointer dereference in setWeiStoreBalance due to the order of conditions in an equality check, and a potential slice bounds out of range panic in encodeFixedWidthUnsignedBigEndian if the big integer exceeds 256 bits.
| } | ||
|
|
||
| k.weiStore.Insert(ctx, addr, sdkmath.NewIntFromBigInt(newStoreBal.ToBig())) | ||
| k.weiStore.Insert(ctx, addr, sdkmath.NewUintFromBigInt(newStoreBal.ToBig())) |
There was a problem hiding this comment.
In setWeiStoreBalance, there is a potential nil pointer dereference panic at line 294:
if weiStoreBalPre.Eq(newStoreBal) || newStoreBal == nil {If newStoreBal is nil (which can happen when setNibiBalanceFromWei is called with a nil wei balance), weiStoreBalPre.Eq(newStoreBal) is evaluated first. Since newStoreBal is nil, calling Eq on it will dereference a nil pointer and panic.
To fix this, the nil check newStoreBal == nil must be placed before weiStoreBalPre.Eq(newStoreBal) to leverage short-circuit evaluation:
if newStoreBal == nil || weiStoreBalPre.Eq(newStoreBal) {| func encodeFixedWidthUnsignedBigEndian(i *big.Int) []byte { | ||
| be := i.Bytes() | ||
| padded := make([]byte, maxIntKeyLen) | ||
| copy(padded[maxIntKeyLen-len(be):], be) | ||
| return padded | ||
| } |
There was a problem hiding this comment.
If i is larger than 256 bits, len(be) will exceed maxIntKeyLen (32). This will cause maxIntKeyLen - len(be) to be negative, resulting in a cryptic runtime slice bounds out of range panic when slicing padded.
Adding an explicit overflow check with a clear panic message improves robustness and makes debugging much easier.
func encodeFixedWidthUnsignedBigEndian(i *big.Int) []byte {
be := i.Bytes()
if len(be) > maxIntKeyLen {
panic(fmt.Sprintf("value overflows max bit length of %d bits", sdkmath.MaxBitLen))
}
padded := make([]byte, maxIntKeyLen)
copy(padded[maxIntKeyLen-len(be):], be)
return padded
}
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Abstract
IntKeyEncoder.Encodefunction panics if the inputmath.Intis nil or negative. #2491collections.IntValueEncoderused to delegate toIntKeyEncoder, which panics on negative or nilsdkmath.Intvalues. That was misleading for signed state (e.g. wei block deltas) and unsafe for callers that expected a general signed int encoder.This PR splits signed value encoding from unsigned fixed-width encoding:
IntValueEncodernow marshals signedsdkmath.Int, a newUintValueEncoderkeeps the existing 32-byte big-endian format for non-negative persisted state, andweiStoreis typed assdkmath.Uint.eth.SignedIntValueEncoderis removed in favor of the generic collections encoder.