diff --git a/chain/chain.go b/chain/chain.go index 2cd49d6..a05ee1b 100644 --- a/chain/chain.go +++ b/chain/chain.go @@ -8,10 +8,11 @@ package chain import ( + "errors" "fmt" - store "forge.lthn.ai/core/go-store" "forge.lthn.ai/core/go-blockchain/types" + store "forge.lthn.ai/core/go-store" ) // Chain manages blockchain storage and indexing. @@ -41,7 +42,7 @@ func (c *Chain) TopBlock() (*types.Block, *BlockMeta, error) { return nil, nil, err } if h == 0 { - return nil, nil, fmt.Errorf("chain: no blocks stored") + return nil, nil, errors.New("chain: no blocks stored") } return c.GetBlockByHeight(h - 1) } diff --git a/chain/difficulty.go b/chain/difficulty.go index 2f4dac9..7f54745 100644 --- a/chain/difficulty.go +++ b/chain/difficulty.go @@ -28,10 +28,7 @@ func (c *Chain) NextDifficulty(height uint64, forks []config.HardFork) (uint64, // LWMA needs N+1 entries (N solve-time intervals). // Start from height 1 — genesis is excluded from the difficulty window. maxLookback := difficulty.LWMAWindow + 1 - lookback := height // height excludes genesis since we start from 1 - if lookback > maxLookback { - lookback = maxLookback - } + lookback := min(height, maxLookback) // height excludes genesis since we start from 1 // Start from max(1, height - lookback) to exclude genesis. startHeight := height - lookback @@ -48,7 +45,7 @@ func (c *Chain) NextDifficulty(height uint64, forks []config.HardFork) (uint64, timestamps := make([]uint64, count) cumulDiffs := make([]*big.Int, count) - for i := 0; i < count; i++ { + for i := range count { meta, err := c.getBlockMeta(startHeight + uint64(i)) if err != nil { // Fewer blocks than expected — use what we have. diff --git a/chain/sync.go b/chain/sync.go index 822fee4..f795fec 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -10,6 +10,7 @@ import ( "context" "encoding/hex" "encoding/json" + "errors" "fmt" "log" "regexp" @@ -66,10 +67,7 @@ func (c *Chain) Sync(ctx context.Context, client *rpc.Client, opts SyncOptions) } remaining := remoteHeight - localHeight - batch := uint64(syncBatchSize) - if remaining < batch { - batch = remaining - } + batch := min(remaining, uint64(syncBatchSize)) blocks, err := client.GetBlocksDetails(localHeight, batch) if err != nil { @@ -413,7 +411,7 @@ var aggregatedRE = regexp.MustCompile(`"AGGREGATED"\s*:\s*\{([^}]+)\}`) func parseBlockHeader(objectInJSON string) (*types.BlockHeader, error) { m := aggregatedRE.FindStringSubmatch(objectInJSON) if m == nil { - return nil, fmt.Errorf("AGGREGATED section not found in object_in_json") + return nil, errors.New("AGGREGATED section not found in object_in_json") } var hj blockHeaderJSON diff --git a/chain/validate.go b/chain/validate.go index 642705d..a52a845 100644 --- a/chain/validate.go +++ b/chain/validate.go @@ -7,6 +7,7 @@ package chain import ( "bytes" + "errors" "fmt" "forge.lthn.ai/core/go-blockchain/config" @@ -31,7 +32,7 @@ func (c *Chain) ValidateHeader(b *types.Block, expectedHeight uint64) error { // Genesis block: prev_id must be zero. if expectedHeight == 0 { if !b.PrevID.IsZero() { - return fmt.Errorf("validate: genesis block has non-zero prev_id") + return errors.New("validate: genesis block has non-zero prev_id") } return nil } diff --git a/consensus/block.go b/consensus/block.go index 8bd8687..0015a5c 100644 --- a/consensus/block.go +++ b/consensus/block.go @@ -7,7 +7,7 @@ package consensus import ( "fmt" - "sort" + "slices" "forge.lthn.ai/core/go-blockchain/config" "forge.lthn.ai/core/go-blockchain/types" @@ -50,7 +50,7 @@ func CheckTimestamp(blockTimestamp uint64, flags uint8, adjustedTime uint64, rec func medianTimestamp(timestamps []uint64) uint64 { sorted := make([]uint64, len(timestamps)) copy(sorted, timestamps) - sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) + slices.Sort(sorted) n := len(sorted) if n == 0 { diff --git a/consensus/pow.go b/consensus/pow.go index 76053f6..16586fd 100644 --- a/consensus/pow.go +++ b/consensus/pow.go @@ -27,7 +27,7 @@ func CheckDifficulty(hash types.Hash, difficulty uint64) bool { // Convert hash to big.Int (little-endian as per CryptoNote convention). // Reverse to big-endian for big.Int. var be [32]byte - for i := 0; i < 32; i++ { + for i := range 32 { be[i] = hash[31-i] } hashInt := new(big.Int).SetBytes(be[:]) diff --git a/consensus/reward.go b/consensus/reward.go index f7dd0ea..efdf0a2 100644 --- a/consensus/reward.go +++ b/consensus/reward.go @@ -6,6 +6,7 @@ package consensus import ( + "errors" "fmt" "math/bits" @@ -55,7 +56,7 @@ func BlockReward(baseReward, blockSize, medianSize uint64) (uint64, error) { // Since hi1 should be 0 for reasonable block sizes, simplify: if hi1 > 0 { - return 0, fmt.Errorf("consensus: reward overflow") + return 0, errors.New("consensus: reward overflow") } hi2, lo2 := bits.Mul64(baseReward, lo1) diff --git a/consensus/verify.go b/consensus/verify.go index 1534c6a..9378f58 100644 --- a/consensus/verify.go +++ b/consensus/verify.go @@ -6,6 +6,7 @@ package consensus import ( + "errors" "fmt" "forge.lthn.ai/core/go-blockchain/config" @@ -222,7 +223,7 @@ func verifyV2Signatures(tx *types.Transaction, getZCRingOutputs ZCRingOutputsFn) // Verify BPP range proof if present. if len(proofs.bppProofBytes) > 0 && len(proofs.bppCommitments) > 0 { if !crypto.VerifyBPP(proofs.bppProofBytes, proofs.bppCommitments) { - return fmt.Errorf("consensus: BPP range proof verification failed") + return errors.New("consensus: BPP range proof verification failed") } } diff --git a/crypto/clsag.go b/crypto/clsag.go index d38b2b0..9791f60 100644 --- a/crypto/clsag.go +++ b/crypto/clsag.go @@ -8,7 +8,7 @@ package crypto import "C" import ( - "fmt" + "errors" "unsafe" ) @@ -20,7 +20,7 @@ func PointMul8(pk [32]byte) ([32]byte, error) { (*C.uint8_t)(unsafe.Pointer(&result[0])), ) if rc != 0 { - return result, fmt.Errorf("crypto: point_mul8 failed") + return result, errors.New("crypto: point_mul8 failed") } return result, nil } @@ -34,7 +34,7 @@ func PointDiv8(pk [32]byte) ([32]byte, error) { (*C.uint8_t)(unsafe.Pointer(&result[0])), ) if rc != 0 { - return result, fmt.Errorf("crypto: point_div8 failed") + return result, errors.New("crypto: point_div8 failed") } return result, nil } @@ -48,7 +48,7 @@ func PointSub(a, b [32]byte) ([32]byte, error) { (*C.uint8_t)(unsafe.Pointer(&result[0])), ) if rc != 0 { - return result, fmt.Errorf("crypto: point_sub failed") + return result, errors.New("crypto: point_sub failed") } return result, nil } @@ -81,7 +81,7 @@ func GenerateCLSAGGG(hash [32]byte, ring []byte, ringSize int, (*C.uint8_t)(unsafe.Pointer(&sig[0])), ) if rc != 0 { - return nil, fmt.Errorf("crypto: generate_CLSAG_GG failed") + return nil, errors.New("crypto: generate_CLSAG_GG failed") } return sig, nil } diff --git a/crypto/keygen.go b/crypto/keygen.go index c0b1a42..5c11dd3 100644 --- a/crypto/keygen.go +++ b/crypto/keygen.go @@ -8,6 +8,7 @@ package crypto import "C" import ( + "errors" "fmt" "unsafe" ) @@ -51,7 +52,7 @@ func GenerateKeyDerivation(pub [32]byte, sec [32]byte) ([32]byte, error) { (*C.uint8_t)(unsafe.Pointer(&d[0])), ) if rc != 0 { - return d, fmt.Errorf("crypto: generate_key_derivation failed") + return d, errors.New("crypto: generate_key_derivation failed") } return d, nil } @@ -66,7 +67,7 @@ func DerivePublicKey(derivation [32]byte, index uint64, base [32]byte) ([32]byte (*C.uint8_t)(unsafe.Pointer(&derived[0])), ) if rc != 0 { - return derived, fmt.Errorf("crypto: derive_public_key failed") + return derived, errors.New("crypto: derive_public_key failed") } return derived, nil } @@ -81,7 +82,7 @@ func DeriveSecretKey(derivation [32]byte, index uint64, base [32]byte) ([32]byte (*C.uint8_t)(unsafe.Pointer(&derived[0])), ) if rc != 0 { - return derived, fmt.Errorf("crypto: derive_secret_key failed") + return derived, errors.New("crypto: derive_secret_key failed") } return derived, nil } diff --git a/crypto/keyimage.go b/crypto/keyimage.go index c844886..961e116 100644 --- a/crypto/keyimage.go +++ b/crypto/keyimage.go @@ -8,7 +8,7 @@ package crypto import "C" import ( - "fmt" + "errors" "unsafe" ) @@ -22,7 +22,7 @@ func GenerateKeyImage(pub [32]byte, sec [32]byte) ([32]byte, error) { (*C.uint8_t)(unsafe.Pointer(&ki[0])), ) if rc != 0 { - return ki, fmt.Errorf("crypto: generate_key_image failed") + return ki, errors.New("crypto: generate_key_image failed") } return ki, nil } diff --git a/crypto/signature.go b/crypto/signature.go index 6d6cb56..664639a 100644 --- a/crypto/signature.go +++ b/crypto/signature.go @@ -8,7 +8,7 @@ package crypto import "C" import ( - "fmt" + "errors" "unsafe" ) @@ -22,7 +22,7 @@ func GenerateSignature(hash [32]byte, pub [32]byte, sec [32]byte) ([64]byte, err (*C.uint8_t)(unsafe.Pointer(&sig[0])), ) if rc != 0 { - return sig, fmt.Errorf("crypto: generate_signature failed") + return sig, errors.New("crypto: generate_signature failed") } return sig, nil } @@ -60,7 +60,7 @@ func GenerateRingSignature(hash [32]byte, image [32]byte, pubs [][32]byte, (*C.uint8_t)(unsafe.Pointer(&flatSigs[0])), ) if rc != 0 { - return nil, fmt.Errorf("crypto: generate_ring_signature failed") + return nil, errors.New("crypto: generate_ring_signature failed") } sigs := make([][64]byte, n) diff --git a/p2p/handshake.go b/p2p/handshake.go index c0737ff..a6f29cc 100644 --- a/p2p/handshake.go +++ b/p2p/handshake.go @@ -79,7 +79,7 @@ type PeerlistEntry struct { func DecodePeerlist(blob []byte) []PeerlistEntry { n := len(blob) / PeerlistEntrySize entries := make([]PeerlistEntry, n) - for i := 0; i < n; i++ { + for i := range n { off := i * PeerlistEntrySize entries[i] = PeerlistEntry{ IP: binary.LittleEndian.Uint32(blob[off : off+4]), diff --git a/p2p/relay.go b/p2p/relay.go index ed436ca..b184fde 100644 --- a/p2p/relay.go +++ b/p2p/relay.go @@ -252,7 +252,7 @@ func (r *ResponseChainEntry) Decode(data []byte) error { func splitHashes(blob []byte, size int) [][]byte { n := len(blob) / size out := make([][]byte, n) - for i := 0; i < n; i++ { + for i := range n { out[i] = blob[i*size : (i+1)*size] } return out diff --git a/tui/explorer_model.go b/tui/explorer_model.go index 5914fd8..0316d20 100644 --- a/tui/explorer_model.go +++ b/tui/explorer_model.go @@ -224,22 +224,13 @@ func (m *ExplorerModel) viewBlockList() string { b.WriteByte('\n') // Visible window centred on cursor. - visibleRows := m.height - 2 // header + bottom margin - if visibleRows < 1 { - visibleRows = 1 - } + visibleRows := max(m.height-2, 1) // header + bottom margin - start := m.cursor - visibleRows/2 - if start < 0 { - start = 0 - } + start := max(m.cursor-visibleRows/2, 0) end := start + visibleRows if end > len(m.rows) { end = len(m.rows) - start = end - visibleRows - if start < 0 { - start = 0 - } + start = max(end-visibleRows, 0) } for i := start; i < end; i++ { @@ -356,13 +347,10 @@ func (m *ExplorerModel) loadBlocks() { } // Show up to 1000 most recent blocks. - count := int(height) - if count > 1000 { - count = 1000 - } + count := min(int(height), 1000) rows := make([]blockRow, count) - for i := 0; i < count; i++ { + for i := range count { h := height - 1 - uint64(i) blk, meta, err := m.chain.GetBlockByHeight(h) if err != nil { @@ -381,9 +369,5 @@ func (m *ExplorerModel) loadBlocks() { // pageSize returns the number of rows to jump for page up/down. func pageSize(height int) int { - n := height - 3 - if n < 1 { - n = 1 - } - return n + return max(height-3, 1) } diff --git a/types/address.go b/types/address.go index cfe878a..d9a2f25 100644 --- a/types/address.go +++ b/types/address.go @@ -170,7 +170,7 @@ func base58Encode(data []byte) string { fullBlocks := len(data) / 8 lastBlockSize := len(data) % 8 - for i := 0; i < fullBlocks; i++ { + for i := range fullBlocks { block := data[i*8 : (i+1)*8] encoded := encodeBlock(block, 11) result = append(result, encoded...) @@ -227,7 +227,7 @@ func base58Decode(s string) ([]byte, error) { var result []byte - for i := 0; i < fullBlocks; i++ { + for i := range fullBlocks { blockStr := s[i*11 : (i+1)*11] decoded, err := decodeBlock(blockStr, 8) if err != nil { diff --git a/wallet/account.go b/wallet/account.go index ce1fc1d..f5be1eb 100644 --- a/wallet/account.go +++ b/wallet/account.go @@ -15,6 +15,7 @@ import ( "crypto/rand" "encoding/hex" "encoding/json" + "errors" "fmt" "io" @@ -54,8 +55,8 @@ type Account struct { SpendSecretKey types.SecretKey `json:"spend_secret_key"` ViewPublicKey types.PublicKey `json:"view_public_key"` ViewSecretKey types.SecretKey `json:"view_secret_key"` - CreatedAt uint64 `json:"created_at"` - Flags uint8 `json:"flags"` + CreatedAt uint64 `json:"created_at"` + Flags uint8 `json:"flags"` } // GenerateAccount creates a new account with random spend keys and a @@ -162,7 +163,7 @@ func LoadAccount(s *store.Store, password string) (*Account, error) { } if len(blob) < saltLen+nonceLen+1 { - return nil, fmt.Errorf("wallet: account data too short") + return nil, errors.New("wallet: account data too short") } salt := blob[:saltLen] diff --git a/wallet/builder.go b/wallet/builder.go index c376165..52532a7 100644 --- a/wallet/builder.go +++ b/wallet/builder.go @@ -11,8 +11,10 @@ package wallet import ( "bytes" + "cmp" + "errors" "fmt" - "sort" + "slices" "forge.lthn.ai/core/go-blockchain/config" "forge.lthn.ai/core/go-blockchain/crypto" @@ -157,20 +159,16 @@ func (b *V1Builder) buildInput(src *Transfer) (types.TxInputToKey, inputMeta, er }) // Sort by global index (consensus rule). - sort.Slice(ring, func(a, b int) bool { - return ring[a].GlobalIndex < ring[b].GlobalIndex + slices.SortFunc(ring, func(a, b RingMember) int { + return cmp.Compare(a.GlobalIndex, b.GlobalIndex) }) // Find real index after sorting. - realIdx := -1 - for j, m := range ring { - if m.GlobalIndex == src.GlobalIndex { - realIdx = j - break - } - } + realIdx := slices.IndexFunc(ring, func(m RingMember) bool { + return m.GlobalIndex == src.GlobalIndex + }) if realIdx < 0 { - return types.TxInputToKey{}, inputMeta{}, fmt.Errorf("real output not found in ring") + return types.TxInputToKey{}, inputMeta{}, errors.New("real output not found in ring") } // Build key offsets and public key list. diff --git a/wallet/mnemonic.go b/wallet/mnemonic.go index 385ccbe..2bc1fff 100644 --- a/wallet/mnemonic.go +++ b/wallet/mnemonic.go @@ -2,6 +2,7 @@ package wallet import ( "encoding/binary" + "errors" "fmt" "hash/crc32" "strings" @@ -43,12 +44,12 @@ func MnemonicDecode(phrase string) ([32]byte, error) { expected := checksumIndex(words[:24]) if words[24] != words[expected] { - return key, fmt.Errorf("wallet: mnemonic checksum failed") + return key, errors.New("wallet: mnemonic checksum failed") } n := uint32(numWords) - for i := 0; i < 8; i++ { + for i := range 8 { w1, ok1 := wordIndex[words[i*3]] w2, ok2 := wordIndex[words[i*3+1]] w3, ok3 := wordIndex[words[i*3+2]] diff --git a/wallet/wallet.go b/wallet/wallet.go index 701f0e6..1df06e9 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -10,15 +10,17 @@ package wallet import ( + "cmp" + "errors" "fmt" - "sort" + "slices" "strconv" - store "forge.lthn.ai/core/go-store" "forge.lthn.ai/core/go-blockchain/chain" "forge.lthn.ai/core/go-blockchain/rpc" "forge.lthn.ai/core/go-blockchain/types" "forge.lthn.ai/core/go-blockchain/wire" + store "forge.lthn.ai/core/go-store" ) const ( @@ -165,7 +167,7 @@ func (w *Wallet) Balance() (confirmed, locked uint64, err error) { // Send constructs and submits a transaction. func (w *Wallet) Send(destinations []Destination, fee uint64) (*types.Transaction, error) { if w.builder == nil || w.client == nil { - return nil, fmt.Errorf("wallet: no RPC client configured") + return nil, errors.New("wallet: no RPC client configured") } chainHeight, err := w.chain.Height() @@ -192,8 +194,8 @@ func (w *Wallet) Send(destinations []Destination, fee uint64) (*types.Transactio spendable = append(spendable, tr) } } - sort.Slice(spendable, func(i, j int) bool { - return spendable[i].Amount > spendable[j].Amount + slices.SortFunc(spendable, func(a, b Transfer) int { + return cmp.Compare(b.Amount, a.Amount) // descending }) var selected []Transfer diff --git a/wire/decoder.go b/wire/decoder.go index d9c824b..94b5987 100644 --- a/wire/decoder.go +++ b/wire/decoder.go @@ -55,7 +55,7 @@ func (d *Decoder) ReadVarint() uint64 { } var val uint64 var shift uint - for i := 0; i < MaxVarintLen; i++ { + for range MaxVarintLen { _, d.err = io.ReadFull(d.r, d.buf[:1]) if d.err != nil { return 0