chore: Go 1.26 modernization #2
21 changed files with 65 additions and 79 deletions
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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[:])
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue