fix(blockchain): upgrade to core v0.8.0-alpha.1 + replace banned imports
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
d004158022
commit
96d60484b6
48 changed files with 365 additions and 391 deletions
|
|
@ -6,11 +6,9 @@
|
||||||
package chain
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/types"
|
"dappco.re/go/core/blockchain/types"
|
||||||
|
|
@ -20,7 +18,7 @@ import (
|
||||||
// MarkSpent records a key image as spent at the given block height.
|
// MarkSpent records a key image as spent at the given block height.
|
||||||
func (c *Chain) MarkSpent(ki types.KeyImage, height uint64) error {
|
func (c *Chain) MarkSpent(ki types.KeyImage, height uint64) error {
|
||||||
if err := c.store.Set(groupSpentKeys, ki.String(), strconv.FormatUint(height, 10)); err != nil {
|
if err := c.store.Set(groupSpentKeys, ki.String(), strconv.FormatUint(height, 10)); err != nil {
|
||||||
return coreerr.E("Chain.MarkSpent", fmt.Sprintf("chain: mark spent %s", ki), err)
|
return coreerr.E("Chain.MarkSpent", core.Sprintf("chain: mark spent %s", ki), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -28,11 +26,11 @@ func (c *Chain) MarkSpent(ki types.KeyImage, height uint64) error {
|
||||||
// IsSpent checks whether a key image has been spent.
|
// IsSpent checks whether a key image has been spent.
|
||||||
func (c *Chain) IsSpent(ki types.KeyImage) (bool, error) {
|
func (c *Chain) IsSpent(ki types.KeyImage) (bool, error) {
|
||||||
_, err := c.store.Get(groupSpentKeys, ki.String())
|
_, err := c.store.Get(groupSpentKeys, ki.String())
|
||||||
if errors.Is(err, store.ErrNotFound) {
|
if core.Is(err, store.ErrNotFound) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, coreerr.E("Chain.IsSpent", fmt.Sprintf("chain: check spent %s", ki), err)
|
return false, coreerr.E("Chain.IsSpent", core.Sprintf("chain: check spent %s", ki), err)
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
@ -56,13 +54,10 @@ func (c *Chain) PutOutput(amount uint64, txID types.Hash, outNo uint32) (uint64,
|
||||||
TxID: txID.String(),
|
TxID: txID.String(),
|
||||||
OutNo: outNo,
|
OutNo: outNo,
|
||||||
}
|
}
|
||||||
val, err := json.Marshal(entry)
|
val := core.JSONMarshalString(entry)
|
||||||
if err != nil {
|
|
||||||
return 0, coreerr.E("Chain.PutOutput", "chain: marshal output", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := strconv.FormatUint(gindex, 10)
|
key := strconv.FormatUint(gindex, 10)
|
||||||
if err := c.store.Set(grp, key, string(val)); err != nil {
|
if err := c.store.Set(grp, key, val); err != nil {
|
||||||
return 0, coreerr.E("Chain.PutOutput", "chain: store output", err)
|
return 0, coreerr.E("Chain.PutOutput", "chain: store output", err)
|
||||||
}
|
}
|
||||||
return gindex, nil
|
return gindex, nil
|
||||||
|
|
@ -74,15 +69,15 @@ func (c *Chain) GetOutput(amount uint64, gindex uint64) (types.Hash, uint32, err
|
||||||
key := strconv.FormatUint(gindex, 10)
|
key := strconv.FormatUint(gindex, 10)
|
||||||
val, err := c.store.Get(grp, key)
|
val, err := c.store.Get(grp, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, store.ErrNotFound) {
|
if core.Is(err, store.ErrNotFound) {
|
||||||
return types.Hash{}, 0, coreerr.E("Chain.GetOutput", fmt.Sprintf("chain: output %d:%d not found", amount, gindex), nil)
|
return types.Hash{}, 0, coreerr.E("Chain.GetOutput", core.Sprintf("chain: output %d:%d not found", amount, gindex), nil)
|
||||||
}
|
}
|
||||||
return types.Hash{}, 0, coreerr.E("Chain.GetOutput", "chain: get output", err)
|
return types.Hash{}, 0, coreerr.E("Chain.GetOutput", "chain: get output", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var entry outputEntry
|
var entry outputEntry
|
||||||
if err := json.Unmarshal([]byte(val), &entry); err != nil {
|
if r := core.JSONUnmarshalString(val, &entry); !r.OK {
|
||||||
return types.Hash{}, 0, coreerr.E("Chain.GetOutput", "chain: unmarshal output", err)
|
return types.Hash{}, 0, coreerr.E("Chain.GetOutput", "chain: unmarshal output", r.Value.(error))
|
||||||
}
|
}
|
||||||
hash, err := types.HashFromHex(entry.TxID)
|
hash, err := types.HashFromHex(entry.TxID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -120,12 +120,12 @@ func (c *Chain) P2PSync(ctx context.Context, conn P2PConnection, opts SyncOption
|
||||||
|
|
||||||
blockDiff, err := c.NextDifficulty(blockHeight, opts.Forks)
|
blockDiff, err := c.NextDifficulty(blockHeight, opts.Forks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Chain.P2PSync", fmt.Sprintf("p2p sync: compute difficulty for block %d", blockHeight), err)
|
return coreerr.E("Chain.P2PSync", core.Sprintf("p2p sync: compute difficulty for block %d", blockHeight), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.processBlockBlobs(entry.Block, entry.Txs,
|
if err := c.processBlockBlobs(entry.Block, entry.Txs,
|
||||||
blockHeight, blockDiff, opts); err != nil {
|
blockHeight, blockDiff, opts); err != nil {
|
||||||
return coreerr.E("Chain.P2PSync", fmt.Sprintf("p2p sync: process block %d", blockHeight), err)
|
return coreerr.E("Chain.P2PSync", core.Sprintf("p2p sync: process block %d", blockHeight), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package chain
|
package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/consensus"
|
"dappco.re/go/core/blockchain/consensus"
|
||||||
|
|
@ -22,27 +21,27 @@ func (c *Chain) GetRingOutputs(amount uint64, offsets []uint64) ([]types.PublicK
|
||||||
for i, gidx := range offsets {
|
for i, gidx := range offsets {
|
||||||
txHash, outNo, err := c.GetOutput(amount, gidx)
|
txHash, outNo, err := c.GetOutput(amount, gidx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("Chain.GetRingOutputs", fmt.Sprintf("ring output %d (amount=%d, gidx=%d)", i, amount, gidx), err)
|
return nil, coreerr.E("Chain.GetRingOutputs", core.Sprintf("ring output %d (amount=%d, gidx=%d)", i, amount, gidx), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, _, err := c.GetTransaction(txHash)
|
tx, _, err := c.GetTransaction(txHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("Chain.GetRingOutputs", fmt.Sprintf("ring output %d: tx %s", i, txHash), err)
|
return nil, coreerr.E("Chain.GetRingOutputs", core.Sprintf("ring output %d: tx %s", i, txHash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(outNo) >= len(tx.Vout) {
|
if int(outNo) >= len(tx.Vout) {
|
||||||
return nil, coreerr.E("Chain.GetRingOutputs", fmt.Sprintf("ring output %d: tx %s has %d outputs, want index %d", i, txHash, len(tx.Vout), outNo), nil)
|
return nil, coreerr.E("Chain.GetRingOutputs", core.Sprintf("ring output %d: tx %s has %d outputs, want index %d", i, txHash, len(tx.Vout), outNo), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch out := tx.Vout[outNo].(type) {
|
switch out := tx.Vout[outNo].(type) {
|
||||||
case types.TxOutputBare:
|
case types.TxOutputBare:
|
||||||
toKey, ok := out.Target.(types.TxOutToKey)
|
toKey, ok := out.Target.(types.TxOutToKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, coreerr.E("Chain.GetRingOutputs", fmt.Sprintf("ring output %d: unsupported target type %T", i, out.Target), nil)
|
return nil, coreerr.E("Chain.GetRingOutputs", core.Sprintf("ring output %d: unsupported target type %T", i, out.Target), nil)
|
||||||
}
|
}
|
||||||
pubs[i] = toKey.Key
|
pubs[i] = toKey.Key
|
||||||
default:
|
default:
|
||||||
return nil, coreerr.E("Chain.GetRingOutputs", fmt.Sprintf("ring output %d: unsupported output type %T", i, out), nil)
|
return nil, coreerr.E("Chain.GetRingOutputs", core.Sprintf("ring output %d: unsupported output type %T", i, out), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pubs, nil
|
return pubs, nil
|
||||||
|
|
@ -58,16 +57,16 @@ func (c *Chain) GetZCRingOutputs(offsets []uint64) ([]consensus.ZCRingMember, er
|
||||||
for i, gidx := range offsets {
|
for i, gidx := range offsets {
|
||||||
txHash, outNo, err := c.GetOutput(0, gidx)
|
txHash, outNo, err := c.GetOutput(0, gidx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("Chain.GetZCRingOutputs", fmt.Sprintf("ZC ring output %d (gidx=%d)", i, gidx), err)
|
return nil, coreerr.E("Chain.GetZCRingOutputs", core.Sprintf("ZC ring output %d (gidx=%d)", i, gidx), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, _, err := c.GetTransaction(txHash)
|
tx, _, err := c.GetTransaction(txHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("Chain.GetZCRingOutputs", fmt.Sprintf("ZC ring output %d: tx %s", i, txHash), err)
|
return nil, coreerr.E("Chain.GetZCRingOutputs", core.Sprintf("ZC ring output %d: tx %s", i, txHash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(outNo) >= len(tx.Vout) {
|
if int(outNo) >= len(tx.Vout) {
|
||||||
return nil, coreerr.E("Chain.GetZCRingOutputs", fmt.Sprintf("ZC ring output %d: tx %s has %d outputs, want index %d", i, txHash, len(tx.Vout), outNo), nil)
|
return nil, coreerr.E("Chain.GetZCRingOutputs", core.Sprintf("ZC ring output %d: tx %s has %d outputs, want index %d", i, txHash, len(tx.Vout), outNo), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch out := tx.Vout[outNo].(type) {
|
switch out := tx.Vout[outNo].(type) {
|
||||||
|
|
@ -78,7 +77,7 @@ func (c *Chain) GetZCRingOutputs(offsets []uint64) ([]consensus.ZCRingMember, er
|
||||||
BlindedAssetID: [32]byte(out.BlindedAssetID),
|
BlindedAssetID: [32]byte(out.BlindedAssetID),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, coreerr.E("Chain.GetZCRingOutputs", fmt.Sprintf("ZC ring output %d: expected TxOutputZarcanum, got %T", i, out), nil)
|
return nil, coreerr.E("Chain.GetZCRingOutputs", core.Sprintf("ZC ring output %d: expected TxOutputZarcanum, got %T", i, out), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return members, nil
|
return members, nil
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,9 @@ package chain
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/types"
|
"dappco.re/go/core/blockchain/types"
|
||||||
|
|
@ -31,7 +29,7 @@ const (
|
||||||
|
|
||||||
// heightKey returns a zero-padded 10-digit decimal key for the given height.
|
// heightKey returns a zero-padded 10-digit decimal key for the given height.
|
||||||
func heightKey(h uint64) string {
|
func heightKey(h uint64) string {
|
||||||
return fmt.Sprintf("%010d", h)
|
return core.Sprintf("%010d", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockRecord is the JSON value stored in the blocks group.
|
// blockRecord is the JSON value stored in the blocks group.
|
||||||
|
|
@ -46,26 +44,23 @@ func (c *Chain) PutBlock(b *types.Block, meta *BlockMeta) error {
|
||||||
enc := wire.NewEncoder(&buf)
|
enc := wire.NewEncoder(&buf)
|
||||||
wire.EncodeBlock(enc, b)
|
wire.EncodeBlock(enc, b)
|
||||||
if err := enc.Err(); err != nil {
|
if err := enc.Err(); err != nil {
|
||||||
return coreerr.E("Chain.PutBlock", fmt.Sprintf("chain: encode block %d", meta.Height), err)
|
return coreerr.E("Chain.PutBlock", core.Sprintf("chain: encode block %d", meta.Height), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rec := blockRecord{
|
rec := blockRecord{
|
||||||
Meta: *meta,
|
Meta: *meta,
|
||||||
Blob: hex.EncodeToString(buf.Bytes()),
|
Blob: hex.EncodeToString(buf.Bytes()),
|
||||||
}
|
}
|
||||||
val, err := json.Marshal(rec)
|
val := core.JSONMarshalString(rec)
|
||||||
if err != nil {
|
|
||||||
return coreerr.E("Chain.PutBlock", fmt.Sprintf("chain: marshal block %d", meta.Height), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.store.Set(groupBlocks, heightKey(meta.Height), string(val)); err != nil {
|
if err := c.store.Set(groupBlocks, heightKey(meta.Height), val); err != nil {
|
||||||
return coreerr.E("Chain.PutBlock", fmt.Sprintf("chain: store block %d", meta.Height), err)
|
return coreerr.E("Chain.PutBlock", core.Sprintf("chain: store block %d", meta.Height), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update hash -> height index.
|
// Update hash -> height index.
|
||||||
hashHex := meta.Hash.String()
|
hashHex := meta.Hash.String()
|
||||||
if err := c.store.Set(groupBlockIndex, hashHex, strconv.FormatUint(meta.Height, 10)); err != nil {
|
if err := c.store.Set(groupBlockIndex, hashHex, strconv.FormatUint(meta.Height, 10)); err != nil {
|
||||||
return coreerr.E("Chain.PutBlock", fmt.Sprintf("chain: index block %d", meta.Height), err)
|
return coreerr.E("Chain.PutBlock", core.Sprintf("chain: index block %d", meta.Height), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -75,10 +70,10 @@ func (c *Chain) PutBlock(b *types.Block, meta *BlockMeta) error {
|
||||||
func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, *BlockMeta, error) {
|
func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, *BlockMeta, error) {
|
||||||
val, err := c.store.Get(groupBlocks, heightKey(height))
|
val, err := c.store.Get(groupBlocks, heightKey(height))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, store.ErrNotFound) {
|
if core.Is(err, store.ErrNotFound) {
|
||||||
return nil, nil, coreerr.E("Chain.GetBlockByHeight", fmt.Sprintf("chain: block %d not found", height), nil)
|
return nil, nil, coreerr.E("Chain.GetBlockByHeight", core.Sprintf("chain: block %d not found", height), nil)
|
||||||
}
|
}
|
||||||
return nil, nil, coreerr.E("Chain.GetBlockByHeight", fmt.Sprintf("chain: get block %d", height), err)
|
return nil, nil, coreerr.E("Chain.GetBlockByHeight", core.Sprintf("chain: get block %d", height), err)
|
||||||
}
|
}
|
||||||
return decodeBlockRecord(val)
|
return decodeBlockRecord(val)
|
||||||
}
|
}
|
||||||
|
|
@ -87,14 +82,14 @@ func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, *BlockMeta, error
|
||||||
func (c *Chain) GetBlockByHash(hash types.Hash) (*types.Block, *BlockMeta, error) {
|
func (c *Chain) GetBlockByHash(hash types.Hash) (*types.Block, *BlockMeta, error) {
|
||||||
heightStr, err := c.store.Get(groupBlockIndex, hash.String())
|
heightStr, err := c.store.Get(groupBlockIndex, hash.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, store.ErrNotFound) {
|
if core.Is(err, store.ErrNotFound) {
|
||||||
return nil, nil, coreerr.E("Chain.GetBlockByHash", fmt.Sprintf("chain: block %s not found", hash), nil)
|
return nil, nil, coreerr.E("Chain.GetBlockByHash", core.Sprintf("chain: block %s not found", hash), nil)
|
||||||
}
|
}
|
||||||
return nil, nil, coreerr.E("Chain.GetBlockByHash", fmt.Sprintf("chain: get block index %s", hash), err)
|
return nil, nil, coreerr.E("Chain.GetBlockByHash", core.Sprintf("chain: get block index %s", hash), err)
|
||||||
}
|
}
|
||||||
height, err := strconv.ParseUint(heightStr, 10, 64)
|
height, err := strconv.ParseUint(heightStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, coreerr.E("Chain.GetBlockByHash", fmt.Sprintf("chain: parse height %q", heightStr), err)
|
return nil, nil, coreerr.E("Chain.GetBlockByHash", core.Sprintf("chain: parse height %q", heightStr), err)
|
||||||
}
|
}
|
||||||
return c.GetBlockByHeight(height)
|
return c.GetBlockByHeight(height)
|
||||||
}
|
}
|
||||||
|
|
@ -111,20 +106,17 @@ func (c *Chain) PutTransaction(hash types.Hash, tx *types.Transaction, meta *TxM
|
||||||
enc := wire.NewEncoder(&buf)
|
enc := wire.NewEncoder(&buf)
|
||||||
wire.EncodeTransaction(enc, tx)
|
wire.EncodeTransaction(enc, tx)
|
||||||
if err := enc.Err(); err != nil {
|
if err := enc.Err(); err != nil {
|
||||||
return coreerr.E("Chain.PutTransaction", fmt.Sprintf("chain: encode tx %s", hash), err)
|
return coreerr.E("Chain.PutTransaction", core.Sprintf("chain: encode tx %s", hash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rec := txRecord{
|
rec := txRecord{
|
||||||
Meta: *meta,
|
Meta: *meta,
|
||||||
Blob: hex.EncodeToString(buf.Bytes()),
|
Blob: hex.EncodeToString(buf.Bytes()),
|
||||||
}
|
}
|
||||||
val, err := json.Marshal(rec)
|
val := core.JSONMarshalString(rec)
|
||||||
if err != nil {
|
|
||||||
return coreerr.E("Chain.PutTransaction", fmt.Sprintf("chain: marshal tx %s", hash), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.store.Set(groupTx, hash.String(), string(val)); err != nil {
|
if err := c.store.Set(groupTx, hash.String(), val); err != nil {
|
||||||
return coreerr.E("Chain.PutTransaction", fmt.Sprintf("chain: store tx %s", hash), err)
|
return coreerr.E("Chain.PutTransaction", core.Sprintf("chain: store tx %s", hash), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -133,15 +125,15 @@ func (c *Chain) PutTransaction(hash types.Hash, tx *types.Transaction, meta *TxM
|
||||||
func (c *Chain) GetTransaction(hash types.Hash) (*types.Transaction, *TxMeta, error) {
|
func (c *Chain) GetTransaction(hash types.Hash) (*types.Transaction, *TxMeta, error) {
|
||||||
val, err := c.store.Get(groupTx, hash.String())
|
val, err := c.store.Get(groupTx, hash.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, store.ErrNotFound) {
|
if core.Is(err, store.ErrNotFound) {
|
||||||
return nil, nil, coreerr.E("Chain.GetTransaction", fmt.Sprintf("chain: tx %s not found", hash), nil)
|
return nil, nil, coreerr.E("Chain.GetTransaction", core.Sprintf("chain: tx %s not found", hash), nil)
|
||||||
}
|
}
|
||||||
return nil, nil, coreerr.E("Chain.GetTransaction", fmt.Sprintf("chain: get tx %s", hash), err)
|
return nil, nil, coreerr.E("Chain.GetTransaction", core.Sprintf("chain: get tx %s", hash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var rec txRecord
|
var rec txRecord
|
||||||
if err := json.Unmarshal([]byte(val), &rec); err != nil {
|
if r := core.JSONUnmarshalString(val, &rec); !r.OK {
|
||||||
return nil, nil, coreerr.E("Chain.GetTransaction", "chain: unmarshal tx", err)
|
return nil, nil, coreerr.E("Chain.GetTransaction", "chain: unmarshal tx", r.Value.(error))
|
||||||
}
|
}
|
||||||
blob, err := hex.DecodeString(rec.Blob)
|
blob, err := hex.DecodeString(rec.Blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -166,19 +158,19 @@ func (c *Chain) HasTransaction(hash types.Hash) bool {
|
||||||
func (c *Chain) getBlockMeta(height uint64) (*BlockMeta, error) {
|
func (c *Chain) getBlockMeta(height uint64) (*BlockMeta, error) {
|
||||||
val, err := c.store.Get(groupBlocks, heightKey(height))
|
val, err := c.store.Get(groupBlocks, heightKey(height))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("Chain.getBlockMeta", fmt.Sprintf("chain: block meta %d", height), err)
|
return nil, coreerr.E("Chain.getBlockMeta", core.Sprintf("chain: block meta %d", height), err)
|
||||||
}
|
}
|
||||||
var rec blockRecord
|
var rec blockRecord
|
||||||
if err := json.Unmarshal([]byte(val), &rec); err != nil {
|
if r := core.JSONUnmarshalString(val, &rec); !r.OK {
|
||||||
return nil, coreerr.E("Chain.getBlockMeta", fmt.Sprintf("chain: unmarshal block meta %d", height), err)
|
return nil, coreerr.E("Chain.getBlockMeta", core.Sprintf("chain: unmarshal block meta %d", height), r.Value.(error))
|
||||||
}
|
}
|
||||||
return &rec.Meta, nil
|
return &rec.Meta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeBlockRecord(val string) (*types.Block, *BlockMeta, error) {
|
func decodeBlockRecord(val string) (*types.Block, *BlockMeta, error) {
|
||||||
var rec blockRecord
|
var rec blockRecord
|
||||||
if err := json.Unmarshal([]byte(val), &rec); err != nil {
|
if r := core.JSONUnmarshalString(val, &rec); !r.OK {
|
||||||
return nil, nil, coreerr.E("decodeBlockRecord", "chain: unmarshal block", err)
|
return nil, nil, coreerr.E("decodeBlockRecord", "chain: unmarshal block", r.Value.(error))
|
||||||
}
|
}
|
||||||
blob, err := hex.DecodeString(rec.Blob)
|
blob, err := hex.DecodeString(rec.Blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -72,16 +71,16 @@ func (c *Chain) Sync(ctx context.Context, client *rpc.Client, opts SyncOptions)
|
||||||
|
|
||||||
blocks, err := client.GetBlocksDetails(localHeight, batch)
|
blocks, err := client.GetBlocksDetails(localHeight, batch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Chain.Sync", fmt.Sprintf("sync: fetch blocks at %d", localHeight), err)
|
return coreerr.E("Chain.Sync", core.Sprintf("sync: fetch blocks at %d", localHeight), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := resolveBlockBlobs(blocks, client); err != nil {
|
if err := resolveBlockBlobs(blocks, client); err != nil {
|
||||||
return coreerr.E("Chain.Sync", fmt.Sprintf("sync: resolve blobs at %d", localHeight), err)
|
return coreerr.E("Chain.Sync", core.Sprintf("sync: resolve blobs at %d", localHeight), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bd := range blocks {
|
for _, bd := range blocks {
|
||||||
if err := c.processBlock(bd, opts); err != nil {
|
if err := c.processBlock(bd, opts); err != nil {
|
||||||
return coreerr.E("Chain.Sync", fmt.Sprintf("sync: process block %d", bd.Height), err)
|
return coreerr.E("Chain.Sync", core.Sprintf("sync: process block %d", bd.Height), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,7 +125,7 @@ func (c *Chain) processBlock(bd rpc.BlockDetails, opts SyncOptions) error {
|
||||||
}
|
}
|
||||||
txBlobBytes, err := hex.DecodeString(txInfo.Blob)
|
txBlobBytes, err := hex.DecodeString(txInfo.Blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Chain.processBlock", fmt.Sprintf("decode tx hex %s", txInfo.ID), err)
|
return coreerr.E("Chain.processBlock", core.Sprintf("decode tx hex %s", txInfo.ID), err)
|
||||||
}
|
}
|
||||||
txBlobs = append(txBlobs, txBlobBytes)
|
txBlobs = append(txBlobs, txBlobBytes)
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +139,7 @@ func (c *Chain) processBlock(bd rpc.BlockDetails, opts SyncOptions) error {
|
||||||
return coreerr.E("Chain.processBlock", "parse daemon block hash", err)
|
return coreerr.E("Chain.processBlock", "parse daemon block hash", err)
|
||||||
}
|
}
|
||||||
if computedHash != daemonHash {
|
if computedHash != daemonHash {
|
||||||
return coreerr.E("Chain.processBlock", fmt.Sprintf("block hash mismatch: computed %s, daemon says %s", computedHash, daemonHash), nil)
|
return coreerr.E("Chain.processBlock", core.Sprintf("block hash mismatch: computed %s, daemon says %s", computedHash, daemonHash), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.processBlockBlobs(blockBlob, txBlobs, bd.Height, diff, opts)
|
return c.processBlockBlobs(blockBlob, txBlobs, bd.Height, diff, opts)
|
||||||
|
|
@ -168,7 +167,7 @@ func (c *Chain) processBlockBlobs(blockBlob []byte, txBlobs [][]byte,
|
||||||
return coreerr.E("Chain.processBlockBlobs", "parse genesis hash", err)
|
return coreerr.E("Chain.processBlockBlobs", "parse genesis hash", err)
|
||||||
}
|
}
|
||||||
if blockHash != genesisHash {
|
if blockHash != genesisHash {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("genesis hash %s does not match expected %s", blockHash, GenesisHash), nil)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("genesis hash %s does not match expected %s", blockHash, GenesisHash), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,27 +211,27 @@ func (c *Chain) processBlockBlobs(blockBlob []byte, txBlobs [][]byte,
|
||||||
txDec := wire.NewDecoder(bytes.NewReader(txBlobData))
|
txDec := wire.NewDecoder(bytes.NewReader(txBlobData))
|
||||||
tx := wire.DecodeTransaction(txDec)
|
tx := wire.DecodeTransaction(txDec)
|
||||||
if err := txDec.Err(); err != nil {
|
if err := txDec.Err(); err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("decode tx wire [%d]", i), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("decode tx wire [%d]", i), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
txHash := wire.TransactionHash(&tx)
|
txHash := wire.TransactionHash(&tx)
|
||||||
|
|
||||||
// Validate transaction semantics.
|
// Validate transaction semantics.
|
||||||
if err := consensus.ValidateTransaction(&tx, txBlobData, opts.Forks, height); err != nil {
|
if err := consensus.ValidateTransaction(&tx, txBlobData, opts.Forks, height); err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("validate tx %s", txHash), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("validate tx %s", txHash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optionally verify signatures using the chain's output index.
|
// Optionally verify signatures using the chain's output index.
|
||||||
if opts.VerifySignatures {
|
if opts.VerifySignatures {
|
||||||
if err := consensus.VerifyTransactionSignatures(&tx, opts.Forks, height, c.GetRingOutputs, c.GetZCRingOutputs); err != nil {
|
if err := consensus.VerifyTransactionSignatures(&tx, opts.Forks, height, c.GetRingOutputs, c.GetZCRingOutputs); err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("verify tx signatures %s", txHash), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("verify tx signatures %s", txHash), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index outputs.
|
// Index outputs.
|
||||||
gindexes, err := c.indexOutputs(txHash, &tx)
|
gindexes, err := c.indexOutputs(txHash, &tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("index tx outputs %s", txHash), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("index tx outputs %s", txHash), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark key images as spent.
|
// Mark key images as spent.
|
||||||
|
|
@ -240,11 +239,11 @@ func (c *Chain) processBlockBlobs(blockBlob []byte, txBlobs [][]byte,
|
||||||
switch inp := vin.(type) {
|
switch inp := vin.(type) {
|
||||||
case types.TxInputToKey:
|
case types.TxInputToKey:
|
||||||
if err := c.MarkSpent(inp.KeyImage, height); err != nil {
|
if err := c.MarkSpent(inp.KeyImage, height); err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("mark spent %s", inp.KeyImage), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("mark spent %s", inp.KeyImage), err)
|
||||||
}
|
}
|
||||||
case types.TxInputZC:
|
case types.TxInputZC:
|
||||||
if err := c.MarkSpent(inp.KeyImage, height); err != nil {
|
if err := c.MarkSpent(inp.KeyImage, height); err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("mark spent %s", inp.KeyImage), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("mark spent %s", inp.KeyImage), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +253,7 @@ func (c *Chain) processBlockBlobs(blockBlob []byte, txBlobs [][]byte,
|
||||||
KeeperBlock: height,
|
KeeperBlock: height,
|
||||||
GlobalOutputIndexes: gindexes,
|
GlobalOutputIndexes: gindexes,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return coreerr.E("Chain.processBlockBlobs", fmt.Sprintf("store tx %s", txHash), err)
|
return coreerr.E("Chain.processBlockBlobs", core.Sprintf("store tx %s", txHash), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,10 +331,10 @@ func resolveBlockBlobs(blocks []rpc.BlockDetails, client *rpc.Client) error {
|
||||||
return coreerr.E("resolveBlockBlobs", "fetch tx blobs", err)
|
return coreerr.E("resolveBlockBlobs", "fetch tx blobs", err)
|
||||||
}
|
}
|
||||||
if len(missed) > 0 {
|
if len(missed) > 0 {
|
||||||
return coreerr.E("resolveBlockBlobs", fmt.Sprintf("daemon missed %d tx(es): %v", len(missed), missed), nil)
|
return coreerr.E("resolveBlockBlobs", core.Sprintf("daemon missed %d tx(es): %v", len(missed), missed), nil)
|
||||||
}
|
}
|
||||||
if len(txHexes) != len(allHashes) {
|
if len(txHexes) != len(allHashes) {
|
||||||
return coreerr.E("resolveBlockBlobs", fmt.Sprintf("expected %d tx blobs, got %d", len(allHashes), len(txHexes)), nil)
|
return coreerr.E("resolveBlockBlobs", core.Sprintf("expected %d tx blobs, got %d", len(allHashes), len(txHexes)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index fetched blobs by hash.
|
// Index fetched blobs by hash.
|
||||||
|
|
@ -363,16 +362,16 @@ func resolveBlockBlobs(blocks []rpc.BlockDetails, client *rpc.Client) error {
|
||||||
// Parse header from object_in_json.
|
// Parse header from object_in_json.
|
||||||
hdr, err := parseBlockHeader(bd.ObjectInJSON)
|
hdr, err := parseBlockHeader(bd.ObjectInJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("resolveBlockBlobs", fmt.Sprintf("block %d: parse header", bd.Height), err)
|
return coreerr.E("resolveBlockBlobs", core.Sprintf("block %d: parse header", bd.Height), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Miner tx blob is transactions_details[0].
|
// Miner tx blob is transactions_details[0].
|
||||||
if len(bd.Transactions) == 0 {
|
if len(bd.Transactions) == 0 {
|
||||||
return coreerr.E("resolveBlockBlobs", fmt.Sprintf("block %d has no transactions_details", bd.Height), nil)
|
return coreerr.E("resolveBlockBlobs", core.Sprintf("block %d has no transactions_details", bd.Height), nil)
|
||||||
}
|
}
|
||||||
minerTxBlob, err := hex.DecodeString(bd.Transactions[0].Blob)
|
minerTxBlob, err := hex.DecodeString(bd.Transactions[0].Blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("resolveBlockBlobs", fmt.Sprintf("block %d: decode miner tx hex", bd.Height), err)
|
return coreerr.E("resolveBlockBlobs", core.Sprintf("block %d: decode miner tx hex", bd.Height), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect regular tx hashes.
|
// Collect regular tx hashes.
|
||||||
|
|
@ -380,7 +379,7 @@ func resolveBlockBlobs(blocks []rpc.BlockDetails, client *rpc.Client) error {
|
||||||
for _, txInfo := range bd.Transactions[1:] {
|
for _, txInfo := range bd.Transactions[1:] {
|
||||||
h, err := types.HashFromHex(txInfo.ID)
|
h, err := types.HashFromHex(txInfo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("resolveBlockBlobs", fmt.Sprintf("block %d: parse tx hash %s", bd.Height, txInfo.ID), err)
|
return coreerr.E("resolveBlockBlobs", core.Sprintf("block %d: parse tx hash %s", bd.Height, txInfo.ID), err)
|
||||||
}
|
}
|
||||||
txHashes = append(txHashes, h)
|
txHashes = append(txHashes, h)
|
||||||
}
|
}
|
||||||
|
|
@ -414,8 +413,8 @@ func parseBlockHeader(objectInJSON string) (*types.BlockHeader, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var hj blockHeaderJSON
|
var hj blockHeaderJSON
|
||||||
if err := json.Unmarshal([]byte("{"+m[1]+"}"), &hj); err != nil {
|
if r := core.JSONUnmarshalString(core.Concat("{", m[1], "}"), &hj); !r.OK {
|
||||||
return nil, coreerr.E("parseBlockHeader", "unmarshal AGGREGATED", err)
|
return nil, coreerr.E("parseBlockHeader", "unmarshal AGGREGATED", r.Value.(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
prevID, err := types.HashFromHex(hj.PrevID)
|
prevID, err := types.HashFromHex(hj.PrevID)
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ package chain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -26,7 +25,7 @@ func (c *Chain) ValidateHeader(b *types.Block, expectedHeight uint64) error {
|
||||||
|
|
||||||
// Height sequence check.
|
// Height sequence check.
|
||||||
if expectedHeight != currentHeight {
|
if expectedHeight != currentHeight {
|
||||||
return coreerr.E("Chain.ValidateHeader", fmt.Sprintf("validate: expected height %d but chain is at %d", expectedHeight, currentHeight), nil)
|
return coreerr.E("Chain.ValidateHeader", core.Sprintf("validate: expected height %d but chain is at %d", expectedHeight, currentHeight), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Genesis block: prev_id must be zero.
|
// Genesis block: prev_id must be zero.
|
||||||
|
|
@ -43,7 +42,7 @@ func (c *Chain) ValidateHeader(b *types.Block, expectedHeight uint64) error {
|
||||||
return coreerr.E("Chain.ValidateHeader", "validate: get top block", err)
|
return coreerr.E("Chain.ValidateHeader", "validate: get top block", err)
|
||||||
}
|
}
|
||||||
if b.PrevID != topMeta.Hash {
|
if b.PrevID != topMeta.Hash {
|
||||||
return coreerr.E("Chain.ValidateHeader", fmt.Sprintf("validate: prev_id %s does not match top block %s", b.PrevID, topMeta.Hash), nil)
|
return coreerr.E("Chain.ValidateHeader", core.Sprintf("validate: prev_id %s does not match top block %s", b.PrevID, topMeta.Hash), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block size check.
|
// Block size check.
|
||||||
|
|
@ -51,7 +50,7 @@ func (c *Chain) ValidateHeader(b *types.Block, expectedHeight uint64) error {
|
||||||
enc := wire.NewEncoder(&buf)
|
enc := wire.NewEncoder(&buf)
|
||||||
wire.EncodeBlock(enc, b)
|
wire.EncodeBlock(enc, b)
|
||||||
if enc.Err() == nil && uint64(buf.Len()) > config.MaxBlockSize {
|
if enc.Err() == nil && uint64(buf.Len()) > config.MaxBlockSize {
|
||||||
return coreerr.E("Chain.ValidateHeader", fmt.Sprintf("validate: block size %d exceeds max %d", buf.Len(), config.MaxBlockSize), nil)
|
return coreerr.E("Chain.ValidateHeader", core.Sprintf("validate: block size %d exceeds max %d", buf.Len(), config.MaxBlockSize), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
cli "dappco.re/go/core/cli/pkg/cli"
|
cli "dappco.re/go/core/cli/pkg/cli"
|
||||||
|
|
@ -38,7 +38,7 @@ func runExplorer(dataDir, seed string, testnet bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dbPath := filepath.Join(dataDir, "chain.db")
|
dbPath := core.JoinPath(dataDir, "chain.db")
|
||||||
s, err := store.New(dbPath)
|
s, err := store.New(dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("runExplorer", "open store", err)
|
return coreerr.E("runExplorer", "open store", err)
|
||||||
|
|
@ -48,7 +48,7 @@ func runExplorer(dataDir, seed string, testnet bool) error {
|
||||||
c := chain.New(s)
|
c := chain.New(s)
|
||||||
cfg, forks := resolveConfig(testnet, &seed)
|
cfg, forks := resolveConfig(testnet, &seed)
|
||||||
|
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
|
||||||
25
cmd_sync.go
25
cmd_sync.go
|
|
@ -7,14 +7,12 @@ package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/chain"
|
"dappco.re/go/core/blockchain/chain"
|
||||||
|
|
@ -55,7 +53,7 @@ func runSyncForeground(dataDir, seed string, testnet bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dbPath := filepath.Join(dataDir, "chain.db")
|
dbPath := core.JoinPath(dataDir, "chain.db")
|
||||||
s, err := store.New(dbPath)
|
s, err := store.New(dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("runSyncForeground", "open store", err)
|
return coreerr.E("runSyncForeground", "open store", err)
|
||||||
|
|
@ -65,7 +63,7 @@ func runSyncForeground(dataDir, seed string, testnet bool) error {
|
||||||
c := chain.New(s)
|
c := chain.New(s)
|
||||||
cfg, forks := resolveConfig(testnet, &seed)
|
cfg, forks := resolveConfig(testnet, &seed)
|
||||||
|
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
log.Println("Starting headless P2P sync...")
|
log.Println("Starting headless P2P sync...")
|
||||||
|
|
@ -79,7 +77,7 @@ func runSyncDaemon(dataDir, seed string, testnet bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pidFile := filepath.Join(dataDir, "sync.pid")
|
pidFile := core.JoinPath(dataDir, "sync.pid")
|
||||||
|
|
||||||
d := process.NewDaemon(process.DaemonOptions{
|
d := process.NewDaemon(process.DaemonOptions{
|
||||||
PIDFile: pidFile,
|
PIDFile: pidFile,
|
||||||
|
|
@ -94,7 +92,7 @@ func runSyncDaemon(dataDir, seed string, testnet bool) error {
|
||||||
return coreerr.E("runSyncDaemon", "daemon start", err)
|
return coreerr.E("runSyncDaemon", "daemon start", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbPath := filepath.Join(dataDir, "chain.db")
|
dbPath := core.JoinPath(dataDir, "chain.db")
|
||||||
s, err := store.New(dbPath)
|
s, err := store.New(dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = d.Stop()
|
_ = d.Stop()
|
||||||
|
|
@ -105,7 +103,7 @@ func runSyncDaemon(dataDir, seed string, testnet bool) error {
|
||||||
c := chain.New(s)
|
c := chain.New(s)
|
||||||
cfg, forks := resolveConfig(testnet, &seed)
|
cfg, forks := resolveConfig(testnet, &seed)
|
||||||
|
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
d.SetReady(true)
|
d.SetReady(true)
|
||||||
|
|
@ -124,19 +122,14 @@ func runSyncDaemon(dataDir, seed string, testnet bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopSyncDaemon(dataDir string) error {
|
func stopSyncDaemon(dataDir string) error {
|
||||||
pidFile := filepath.Join(dataDir, "sync.pid")
|
pidFile := core.JoinPath(dataDir, "sync.pid")
|
||||||
pid, running := process.ReadPID(pidFile)
|
pid, running := process.ReadPID(pidFile)
|
||||||
if pid == 0 || !running {
|
if pid == 0 || !running {
|
||||||
return coreerr.E("stopSyncDaemon", "no running sync daemon found", nil)
|
return coreerr.E("stopSyncDaemon", "no running sync daemon found", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := os.FindProcess(pid)
|
if err := syscall.Kill(pid, syscall.SIGTERM); err != nil {
|
||||||
if err != nil {
|
return coreerr.E("stopSyncDaemon", core.Sprintf("signal process %d", pid), err)
|
||||||
return coreerr.E("stopSyncDaemon", fmt.Sprintf("find process %d", pid), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := proc.Signal(syscall.SIGTERM); err != nil {
|
|
||||||
return coreerr.E("stopSyncDaemon", fmt.Sprintf("signal process %d", pid), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Sent SIGTERM to sync daemon (PID %d)", pid)
|
log.Printf("Sent SIGTERM to sync daemon (PID %d)", pid)
|
||||||
|
|
|
||||||
10
commands.go
10
commands.go
|
|
@ -6,9 +6,7 @@
|
||||||
package blockchain
|
package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"dappco.re/go/core"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
coreio "dappco.re/go/core/io"
|
coreio "dappco.re/go/core/io"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
|
|
@ -54,11 +52,11 @@ func resolveConfig(testnet bool, seed *string) (config.ChainConfig, []config.Har
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultDataDir() string {
|
func defaultDataDir() string {
|
||||||
home, err := os.UserHomeDir()
|
home := core.Env("DIR_HOME")
|
||||||
if err != nil {
|
if home == "" {
|
||||||
return ".lethean"
|
return ".lethean"
|
||||||
}
|
}
|
||||||
return filepath.Join(home, ".lethean", "chain")
|
return core.JoinPath(home, ".lethean", "chain")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureDataDir(dataDir string) error {
|
func ensureDataDir(dataDir string) error {
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -30,7 +30,7 @@ func CheckTimestamp(blockTimestamp uint64, flags uint8, adjustedTime uint64, rec
|
||||||
limit = config.PosBlockFutureTimeLimit
|
limit = config.PosBlockFutureTimeLimit
|
||||||
}
|
}
|
||||||
if blockTimestamp > adjustedTime+limit {
|
if blockTimestamp > adjustedTime+limit {
|
||||||
return coreerr.E("CheckTimestamp", fmt.Sprintf("%d > %d + %d",
|
return coreerr.E("CheckTimestamp", core.Sprintf("%d > %d + %d",
|
||||||
blockTimestamp, adjustedTime, limit), ErrTimestampFuture)
|
blockTimestamp, adjustedTime, limit), ErrTimestampFuture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ func CheckTimestamp(blockTimestamp uint64, flags uint8, adjustedTime uint64, rec
|
||||||
|
|
||||||
median := medianTimestamp(recentTimestamps)
|
median := medianTimestamp(recentTimestamps)
|
||||||
if blockTimestamp < median {
|
if blockTimestamp < median {
|
||||||
return coreerr.E("CheckTimestamp", fmt.Sprintf("%d < median %d",
|
return coreerr.E("CheckTimestamp", core.Sprintf("%d < median %d",
|
||||||
blockTimestamp, median), ErrTimestampOld)
|
blockTimestamp, median), ErrTimestampOld)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ func ValidateMinerTx(tx *types.Transaction, height uint64, forks []config.HardFo
|
||||||
return coreerr.E("ValidateMinerTx", "first input is not txin_gen", ErrMinerTxInputs)
|
return coreerr.E("ValidateMinerTx", "first input is not txin_gen", ErrMinerTxInputs)
|
||||||
}
|
}
|
||||||
if gen.Height != height {
|
if gen.Height != height {
|
||||||
return coreerr.E("ValidateMinerTx", fmt.Sprintf("got %d, expected %d", gen.Height, height), ErrMinerTxHeight)
|
return coreerr.E("ValidateMinerTx", core.Sprintf("got %d, expected %d", gen.Height, height), ErrMinerTxHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoW blocks: exactly 1 input. PoS: exactly 2.
|
// PoW blocks: exactly 1 input. PoS: exactly 2.
|
||||||
|
|
@ -94,7 +94,7 @@ func ValidateMinerTx(tx *types.Transaction, height uint64, forks []config.HardFo
|
||||||
// Post-HF4: accept ZC inputs.
|
// Post-HF4: accept ZC inputs.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return coreerr.E("ValidateMinerTx", fmt.Sprintf("%d inputs (expected 1 or 2)", len(tx.Vin)), ErrMinerTxInputs)
|
return coreerr.E("ValidateMinerTx", core.Sprintf("%d inputs (expected 1 or 2)", len(tx.Vin)), ErrMinerTxInputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -121,7 +121,7 @@ func ValidateBlockReward(minerTx *types.Transaction, height, blockSize, medianSi
|
||||||
}
|
}
|
||||||
|
|
||||||
if outputSum > expected {
|
if outputSum > expected {
|
||||||
return coreerr.E("ValidateBlockReward", fmt.Sprintf("outputs %d > expected %d", outputSum, expected), ErrRewardMismatch)
|
return coreerr.E("ValidateBlockReward", core.Sprintf("outputs %d > expected %d", outputSum, expected), ErrRewardMismatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -152,7 +152,7 @@ func expectedBlockMajorVersion(forks []config.HardFork, height uint64) uint8 {
|
||||||
func checkBlockVersion(blk *types.Block, forks []config.HardFork, height uint64) error {
|
func checkBlockVersion(blk *types.Block, forks []config.HardFork, height uint64) error {
|
||||||
expected := expectedBlockMajorVersion(forks, height)
|
expected := expectedBlockMajorVersion(forks, height)
|
||||||
if blk.MajorVersion != expected {
|
if blk.MajorVersion != expected {
|
||||||
return coreerr.E("checkBlockVersion", fmt.Sprintf("got %d, want %d at height %d",
|
return coreerr.E("checkBlockVersion", core.Sprintf("got %d, want %d at height %d",
|
||||||
blk.MajorVersion, expected, height), ErrBlockMajorVersion)
|
blk.MajorVersion, expected, height), ErrBlockMajorVersion)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -226,7 +226,7 @@ func IsPreHardforkFreeze(forks []config.HardFork, version uint8, height uint64)
|
||||||
func ValidateTransactionInBlock(tx *types.Transaction, txBlob []byte, forks []config.HardFork, height uint64) error {
|
func ValidateTransactionInBlock(tx *types.Transaction, txBlob []byte, forks []config.HardFork, height uint64) error {
|
||||||
// Pre-hardfork freeze: reject non-coinbase transactions in the freeze window.
|
// Pre-hardfork freeze: reject non-coinbase transactions in the freeze window.
|
||||||
if !isCoinbase(tx) && IsPreHardforkFreeze(forks, config.HF5, height) {
|
if !isCoinbase(tx) && IsPreHardforkFreeze(forks, config.HF5, height) {
|
||||||
return coreerr.E("ValidateTransactionInBlock", fmt.Sprintf("height %d is within HF5 freeze window", height), ErrPreHardforkFreeze)
|
return coreerr.E("ValidateTransactionInBlock", core.Sprintf("height %d is within HF5 freeze window", height), ErrPreHardforkFreeze)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ValidateTransaction(tx, txBlob, forks, height)
|
return ValidateTransaction(tx, txBlob, forks, height)
|
||||||
|
|
|
||||||
|
|
@ -5,39 +5,39 @@
|
||||||
|
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import "errors"
|
import "dappco.re/go/core"
|
||||||
|
|
||||||
// Sentinel errors for consensus validation failures.
|
// Sentinel errors for consensus validation failures.
|
||||||
var (
|
var (
|
||||||
// Transaction structural errors.
|
// Transaction structural errors.
|
||||||
ErrTxTooLarge = errors.New("consensus: transaction too large")
|
ErrTxTooLarge = core.E("", "consensus: transaction too large", nil)
|
||||||
ErrNoInputs = errors.New("consensus: transaction has no inputs")
|
ErrNoInputs = core.E("", "consensus: transaction has no inputs", nil)
|
||||||
ErrTooManyInputs = errors.New("consensus: transaction exceeds max inputs")
|
ErrTooManyInputs = core.E("", "consensus: transaction exceeds max inputs", nil)
|
||||||
ErrInvalidInputType = errors.New("consensus: unsupported input type")
|
ErrInvalidInputType = core.E("", "consensus: unsupported input type", nil)
|
||||||
ErrNoOutputs = errors.New("consensus: transaction has no outputs")
|
ErrNoOutputs = core.E("", "consensus: transaction has no outputs", nil)
|
||||||
ErrTooFewOutputs = errors.New("consensus: transaction below min outputs")
|
ErrTooFewOutputs = core.E("", "consensus: transaction below min outputs", nil)
|
||||||
ErrTooManyOutputs = errors.New("consensus: transaction exceeds max outputs")
|
ErrTooManyOutputs = core.E("", "consensus: transaction exceeds max outputs", nil)
|
||||||
ErrInvalidOutput = errors.New("consensus: invalid output")
|
ErrInvalidOutput = core.E("", "consensus: invalid output", nil)
|
||||||
ErrDuplicateKeyImage = errors.New("consensus: duplicate key image in transaction")
|
ErrDuplicateKeyImage = core.E("", "consensus: duplicate key image in transaction", nil)
|
||||||
ErrInvalidExtra = errors.New("consensus: invalid extra field")
|
ErrInvalidExtra = core.E("", "consensus: invalid extra field", nil)
|
||||||
ErrTxVersionInvalid = errors.New("consensus: invalid transaction version for current hardfork")
|
ErrTxVersionInvalid = core.E("", "consensus: invalid transaction version for current hardfork", nil)
|
||||||
ErrPreHardforkFreeze = errors.New("consensus: non-coinbase transaction rejected during pre-hardfork freeze")
|
ErrPreHardforkFreeze = core.E("", "consensus: non-coinbase transaction rejected during pre-hardfork freeze", nil)
|
||||||
|
|
||||||
// Transaction economic errors.
|
// Transaction economic errors.
|
||||||
ErrInputOverflow = errors.New("consensus: input amount overflow")
|
ErrInputOverflow = core.E("", "consensus: input amount overflow", nil)
|
||||||
ErrOutputOverflow = errors.New("consensus: output amount overflow")
|
ErrOutputOverflow = core.E("", "consensus: output amount overflow", nil)
|
||||||
ErrNegativeFee = errors.New("consensus: outputs exceed inputs")
|
ErrNegativeFee = core.E("", "consensus: outputs exceed inputs", nil)
|
||||||
|
|
||||||
// Block errors.
|
// Block errors.
|
||||||
ErrBlockTooLarge = errors.New("consensus: block exceeds max size")
|
ErrBlockTooLarge = core.E("", "consensus: block exceeds max size", nil)
|
||||||
ErrBlockMajorVersion = errors.New("consensus: invalid block major version for height")
|
ErrBlockMajorVersion = core.E("", "consensus: invalid block major version for height", nil)
|
||||||
ErrTimestampFuture = errors.New("consensus: block timestamp too far in future")
|
ErrTimestampFuture = core.E("", "consensus: block timestamp too far in future", nil)
|
||||||
ErrTimestampOld = errors.New("consensus: block timestamp below median")
|
ErrTimestampOld = core.E("", "consensus: block timestamp below median", nil)
|
||||||
ErrMinerTxInputs = errors.New("consensus: invalid miner transaction inputs")
|
ErrMinerTxInputs = core.E("", "consensus: invalid miner transaction inputs", nil)
|
||||||
ErrMinerTxHeight = errors.New("consensus: miner transaction height mismatch")
|
ErrMinerTxHeight = core.E("", "consensus: miner transaction height mismatch", nil)
|
||||||
ErrMinerTxUnlock = errors.New("consensus: miner transaction unlock time invalid")
|
ErrMinerTxUnlock = core.E("", "consensus: miner transaction unlock time invalid", nil)
|
||||||
ErrRewardMismatch = errors.New("consensus: block reward mismatch")
|
ErrRewardMismatch = core.E("", "consensus: block reward mismatch", nil)
|
||||||
ErrMinerTxProofs = errors.New("consensus: miner transaction proof count invalid")
|
ErrMinerTxProofs = core.E("", "consensus: miner transaction proof count invalid", nil)
|
||||||
|
|
||||||
// ErrBlockVersion is an alias for ErrBlockMajorVersion, used by
|
// ErrBlockVersion is an alias for ErrBlockMajorVersion, used by
|
||||||
// checkBlockVersion when the block major version does not match
|
// checkBlockVersion when the block major version does not match
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/types"
|
"dappco.re/go/core/blockchain/types"
|
||||||
|
|
@ -33,7 +33,7 @@ func TxFee(tx *types.Transaction) (uint64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if outputSum > inputSum {
|
if outputSum > inputSum {
|
||||||
return 0, coreerr.E("TxFee", fmt.Sprintf("inputs=%d, outputs=%d", inputSum, outputSum), ErrNegativeFee)
|
return 0, coreerr.E("TxFee", core.Sprintf("inputs=%d, outputs=%d", inputSum, outputSum), ErrNegativeFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputSum - outputSum, nil
|
return inputSum - outputSum, nil
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -44,7 +44,7 @@ func BlockReward(baseReward, blockSize, medianSize uint64) (uint64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if blockSize > 2*effectiveMedian {
|
if blockSize > 2*effectiveMedian {
|
||||||
return 0, coreerr.E("BlockReward", fmt.Sprintf("consensus: block size %d too large for median %d", blockSize, effectiveMedian), nil)
|
return 0, coreerr.E("BlockReward", core.Sprintf("consensus: block size %d too large for median %d", blockSize, effectiveMedian), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// penalty = baseReward * (2*median - size) * size / median²
|
// penalty = baseReward * (2*median - size) * size / median²
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -26,7 +25,7 @@ func ValidateTransaction(tx *types.Transaction, txBlob []byte, forks []config.Ha
|
||||||
|
|
||||||
// 1. Blob size.
|
// 1. Blob size.
|
||||||
if uint64(len(txBlob)) >= config.MaxTransactionBlobSize {
|
if uint64(len(txBlob)) >= config.MaxTransactionBlobSize {
|
||||||
return coreerr.E("ValidateTransaction", fmt.Sprintf("%d bytes", len(txBlob)), ErrTxTooLarge)
|
return coreerr.E("ValidateTransaction", core.Sprintf("%d bytes", len(txBlob)), ErrTxTooLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Input count.
|
// 2. Input count.
|
||||||
|
|
@ -34,7 +33,7 @@ func ValidateTransaction(tx *types.Transaction, txBlob []byte, forks []config.Ha
|
||||||
return ErrNoInputs
|
return ErrNoInputs
|
||||||
}
|
}
|
||||||
if uint64(len(tx.Vin)) > config.TxMaxAllowedInputs {
|
if uint64(len(tx.Vin)) > config.TxMaxAllowedInputs {
|
||||||
return coreerr.E("ValidateTransaction", fmt.Sprintf("%d", len(tx.Vin)), ErrTooManyInputs)
|
return coreerr.E("ValidateTransaction", core.Sprintf("%d", len(tx.Vin)), ErrTooManyInputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
hf1Active := config.IsHardForkActive(forks, config.HF1, height)
|
hf1Active := config.IsHardForkActive(forks, config.HF1, height)
|
||||||
|
|
@ -82,13 +81,13 @@ func checkTxVersion(tx *types.Transaction, forks []config.HardFork, height uint6
|
||||||
|
|
||||||
if hf5Active && tx.Version < types.VersionPostHF5 {
|
if hf5Active && tx.Version < types.VersionPostHF5 {
|
||||||
return coreerr.E("checkTxVersion",
|
return coreerr.E("checkTxVersion",
|
||||||
fmt.Sprintf("version %d too low after HF5 at height %d", tx.Version, height),
|
core.Sprintf("version %d too low after HF5 at height %d", tx.Version, height),
|
||||||
ErrTxVersionInvalid)
|
ErrTxVersionInvalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hf5Active && tx.Version >= types.VersionPostHF5 {
|
if !hf5Active && tx.Version >= types.VersionPostHF5 {
|
||||||
return coreerr.E("checkTxVersion",
|
return coreerr.E("checkTxVersion",
|
||||||
fmt.Sprintf("version %d not allowed before HF5 at height %d", tx.Version, height),
|
core.Sprintf("version %d not allowed before HF5 at height %d", tx.Version, height),
|
||||||
ErrTxVersionInvalid)
|
ErrTxVersionInvalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,12 +104,12 @@ func checkInputTypes(tx *types.Transaction, hf1Active, hf4Active bool) error {
|
||||||
case types.TxInputHTLC, types.TxInputMultisig:
|
case types.TxInputHTLC, types.TxInputMultisig:
|
||||||
// HTLC and multisig inputs require at least HF1.
|
// HTLC and multisig inputs require at least HF1.
|
||||||
if !hf1Active {
|
if !hf1Active {
|
||||||
return coreerr.E("checkInputTypes", fmt.Sprintf("tag %d pre-HF1", vin.InputType()), ErrInvalidInputType)
|
return coreerr.E("checkInputTypes", core.Sprintf("tag %d pre-HF1", vin.InputType()), ErrInvalidInputType)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Future types (ZC) — accept if HF4+.
|
// Future types (ZC) — accept if HF4+.
|
||||||
if !hf4Active {
|
if !hf4Active {
|
||||||
return coreerr.E("checkInputTypes", fmt.Sprintf("tag %d pre-HF4", vin.InputType()), ErrInvalidInputType)
|
return coreerr.E("checkInputTypes", core.Sprintf("tag %d pre-HF4", vin.InputType()), ErrInvalidInputType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,24 +122,24 @@ func checkOutputs(tx *types.Transaction, hf1Active, hf4Active bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if hf4Active && uint64(len(tx.Vout)) < config.TxMinAllowedOutputs {
|
if hf4Active && uint64(len(tx.Vout)) < config.TxMinAllowedOutputs {
|
||||||
return coreerr.E("checkOutputs", fmt.Sprintf("%d (min %d)", len(tx.Vout), config.TxMinAllowedOutputs), ErrTooFewOutputs)
|
return coreerr.E("checkOutputs", core.Sprintf("%d (min %d)", len(tx.Vout), config.TxMinAllowedOutputs), ErrTooFewOutputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if uint64(len(tx.Vout)) > config.TxMaxAllowedOutputs {
|
if uint64(len(tx.Vout)) > config.TxMaxAllowedOutputs {
|
||||||
return coreerr.E("checkOutputs", fmt.Sprintf("%d", len(tx.Vout)), ErrTooManyOutputs)
|
return coreerr.E("checkOutputs", core.Sprintf("%d", len(tx.Vout)), ErrTooManyOutputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, vout := range tx.Vout {
|
for i, vout := range tx.Vout {
|
||||||
switch o := vout.(type) {
|
switch o := vout.(type) {
|
||||||
case types.TxOutputBare:
|
case types.TxOutputBare:
|
||||||
if o.Amount == 0 {
|
if o.Amount == 0 {
|
||||||
return coreerr.E("checkOutputs", fmt.Sprintf("output %d has zero amount", i), ErrInvalidOutput)
|
return coreerr.E("checkOutputs", core.Sprintf("output %d has zero amount", i), ErrInvalidOutput)
|
||||||
}
|
}
|
||||||
// HTLC and Multisig output targets require at least HF1.
|
// HTLC and Multisig output targets require at least HF1.
|
||||||
switch o.Target.(type) {
|
switch o.Target.(type) {
|
||||||
case types.TxOutHTLC, types.TxOutMultisig:
|
case types.TxOutHTLC, types.TxOutMultisig:
|
||||||
if !hf1Active {
|
if !hf1Active {
|
||||||
return coreerr.E("checkOutputs", fmt.Sprintf("output %d: HTLC/multisig target pre-HF1", i), ErrInvalidOutput)
|
return coreerr.E("checkOutputs", core.Sprintf("output %d: HTLC/multisig target pre-HF1", i), ErrInvalidOutput)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case types.TxOutputZarcanum:
|
case types.TxOutputZarcanum:
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/types"
|
"dappco.re/go/core/blockchain/types"
|
||||||
|
|
@ -47,7 +46,7 @@ func parseV2Signatures(raw []byte) ([]v2SigEntry, error) {
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
tag := dec.ReadUint8()
|
tag := dec.ReadUint8()
|
||||||
if dec.Err() != nil {
|
if dec.Err() != nil {
|
||||||
return nil, coreerr.E("parseV2Signatures", fmt.Sprintf("read sig tag %d", i), dec.Err())
|
return nil, coreerr.E("parseV2Signatures", core.Sprintf("read sig tag %d", i), dec.Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
entry := v2SigEntry{tag: tag}
|
entry := v2SigEntry{tag: tag}
|
||||||
|
|
@ -56,7 +55,7 @@ func parseV2Signatures(raw []byte) ([]v2SigEntry, error) {
|
||||||
case types.SigTypeZC:
|
case types.SigTypeZC:
|
||||||
zc, err := parseZCSig(dec)
|
zc, err := parseZCSig(dec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("parseV2Signatures", fmt.Sprintf("parse ZC_sig %d", i), err)
|
return nil, coreerr.E("parseV2Signatures", core.Sprintf("parse ZC_sig %d", i), err)
|
||||||
}
|
}
|
||||||
entry.zcSig = zc
|
entry.zcSig = zc
|
||||||
|
|
||||||
|
|
@ -76,11 +75,11 @@ func parseV2Signatures(raw []byte) ([]v2SigEntry, error) {
|
||||||
skipZarcanumSig(dec)
|
skipZarcanumSig(dec)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, coreerr.E("parseV2Signatures", fmt.Sprintf("unsupported sig tag 0x%02x", tag), nil)
|
return nil, coreerr.E("parseV2Signatures", core.Sprintf("unsupported sig tag 0x%02x", tag), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dec.Err() != nil {
|
if dec.Err() != nil {
|
||||||
return nil, coreerr.E("parseV2Signatures", fmt.Sprintf("parse sig %d (tag 0x%02x)", i, tag), dec.Err())
|
return nil, coreerr.E("parseV2Signatures", core.Sprintf("parse sig %d (tag 0x%02x)", i, tag), dec.Err())
|
||||||
}
|
}
|
||||||
entries = append(entries, entry)
|
entries = append(entries, entry)
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +118,7 @@ func parseZCSig(dec *wire.Decoder) (*zcSigData, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if rgCount != rxCount {
|
if rgCount != rxCount {
|
||||||
return nil, coreerr.E("parseZCSig", fmt.Sprintf("CLSAG r_g count %d != r_x count %d", rgCount, rxCount), nil)
|
return nil, coreerr.E("parseZCSig", core.Sprintf("CLSAG r_g count %d != r_x count %d", rgCount, rxCount), nil)
|
||||||
}
|
}
|
||||||
zc.ringSize = int(rgCount)
|
zc.ringSize = int(rgCount)
|
||||||
|
|
||||||
|
|
@ -205,7 +204,7 @@ func parseV2Proofs(raw []byte) (*v2ProofData, error) {
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
tag := dec.ReadUint8()
|
tag := dec.ReadUint8()
|
||||||
if dec.Err() != nil {
|
if dec.Err() != nil {
|
||||||
return nil, coreerr.E("parseV2Proofs", fmt.Sprintf("read proof tag %d", i), dec.Err())
|
return nil, coreerr.E("parseV2Proofs", core.Sprintf("read proof tag %d", i), dec.Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
|
|
@ -218,7 +217,7 @@ func parseV2Proofs(raw []byte) (*v2ProofData, error) {
|
||||||
for j := uint64(0); j < nBGE; j++ {
|
for j := uint64(0); j < nBGE; j++ {
|
||||||
data.bgeProofs[j] = readBGEProofBytes(dec)
|
data.bgeProofs[j] = readBGEProofBytes(dec)
|
||||||
if dec.Err() != nil {
|
if dec.Err() != nil {
|
||||||
return nil, coreerr.E("parseV2Proofs", fmt.Sprintf("parse BGE proof %d", j), dec.Err())
|
return nil, coreerr.E("parseV2Proofs", core.Sprintf("parse BGE proof %d", j), dec.Err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +238,7 @@ func parseV2Proofs(raw []byte) (*v2ProofData, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, coreerr.E("parseV2Proofs", fmt.Sprintf("unsupported proof tag 0x%02x", tag), nil)
|
return nil, coreerr.E("parseV2Proofs", core.Sprintf("unsupported proof tag 0x%02x", tag), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -71,7 +70,7 @@ func verifyV1Signatures(tx *types.Transaction, getRingOutputs RingOutputsFn) err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tx.Signatures) != ringInputCount {
|
if len(tx.Signatures) != ringInputCount {
|
||||||
return coreerr.E("verifyV1Signatures", fmt.Sprintf("consensus: signature count %d != input count %d", len(tx.Signatures), ringInputCount), nil)
|
return coreerr.E("verifyV1Signatures", core.Sprintf("consensus: signature count %d != input count %d", len(tx.Signatures), ringInputCount), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual NLSAG verification requires the crypto bridge and ring outputs.
|
// Actual NLSAG verification requires the crypto bridge and ring outputs.
|
||||||
|
|
@ -110,12 +109,12 @@ func verifyV1Signatures(tx *types.Transaction, getRingOutputs RingOutputsFn) err
|
||||||
|
|
||||||
ringKeys, err := getRingOutputs(amount, offsets)
|
ringKeys, err := getRingOutputs(amount, offsets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("verifyV1Signatures", fmt.Sprintf("consensus: failed to fetch ring outputs for input %d", sigIdx), err)
|
return coreerr.E("verifyV1Signatures", core.Sprintf("consensus: failed to fetch ring outputs for input %d", sigIdx), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ringSigs := tx.Signatures[sigIdx]
|
ringSigs := tx.Signatures[sigIdx]
|
||||||
if len(ringSigs) != len(ringKeys) {
|
if len(ringSigs) != len(ringKeys) {
|
||||||
return coreerr.E("verifyV1Signatures", fmt.Sprintf("consensus: input %d has %d signatures but ring size %d", sigIdx, len(ringSigs), len(ringKeys)), nil)
|
return coreerr.E("verifyV1Signatures", core.Sprintf("consensus: input %d has %d signatures but ring size %d", sigIdx, len(ringSigs), len(ringKeys)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert typed slices to raw byte arrays for the crypto bridge.
|
// Convert typed slices to raw byte arrays for the crypto bridge.
|
||||||
|
|
@ -130,7 +129,7 @@ func verifyV1Signatures(tx *types.Transaction, getRingOutputs RingOutputsFn) err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !crypto.CheckRingSignature([32]byte(prefixHash), [32]byte(keyImage), pubs, sigs) {
|
if !crypto.CheckRingSignature([32]byte(prefixHash), [32]byte(keyImage), pubs, sigs) {
|
||||||
return coreerr.E("verifyV1Signatures", fmt.Sprintf("consensus: ring signature verification failed for input %d", sigIdx), nil)
|
return coreerr.E("verifyV1Signatures", core.Sprintf("consensus: ring signature verification failed for input %d", sigIdx), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
sigIdx++
|
sigIdx++
|
||||||
|
|
@ -149,7 +148,7 @@ func verifyV2Signatures(tx *types.Transaction, getZCRingOutputs ZCRingOutputsFn)
|
||||||
|
|
||||||
// Match signatures to inputs: each input must have a corresponding signature.
|
// Match signatures to inputs: each input must have a corresponding signature.
|
||||||
if len(sigEntries) != len(tx.Vin) {
|
if len(sigEntries) != len(tx.Vin) {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: V2 signature count %d != input count %d", len(sigEntries), len(tx.Vin)), nil)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: V2 signature count %d != input count %d", len(sigEntries), len(tx.Vin)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that ZC inputs have ZC_sig and vice versa.
|
// Validate that ZC inputs have ZC_sig and vice versa.
|
||||||
|
|
@ -157,11 +156,11 @@ func verifyV2Signatures(tx *types.Transaction, getZCRingOutputs ZCRingOutputsFn)
|
||||||
switch vin.(type) {
|
switch vin.(type) {
|
||||||
case types.TxInputZC:
|
case types.TxInputZC:
|
||||||
if sigEntries[i].tag != types.SigTypeZC {
|
if sigEntries[i].tag != types.SigTypeZC {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: input %d is ZC but signature tag is 0x%02x", i, sigEntries[i].tag), nil)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: input %d is ZC but signature tag is 0x%02x", i, sigEntries[i].tag), nil)
|
||||||
}
|
}
|
||||||
case types.TxInputToKey:
|
case types.TxInputToKey:
|
||||||
if sigEntries[i].tag != types.SigTypeNLSAG && sigEntries[i].tag != types.SigTypeVoid {
|
if sigEntries[i].tag != types.SigTypeNLSAG && sigEntries[i].tag != types.SigTypeVoid {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: input %d is to_key but signature tag is 0x%02x", i, sigEntries[i].tag), nil)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: input %d is to_key but signature tag is 0x%02x", i, sigEntries[i].tag), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +184,7 @@ func verifyV2Signatures(tx *types.Transaction, getZCRingOutputs ZCRingOutputsFn)
|
||||||
|
|
||||||
zc := sigEntries[i].zcSig
|
zc := sigEntries[i].zcSig
|
||||||
if zc == nil {
|
if zc == nil {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: input %d: missing ZC_sig data", i), nil)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: input %d: missing ZC_sig data", i), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract absolute global indices from key offsets.
|
// Extract absolute global indices from key offsets.
|
||||||
|
|
@ -196,11 +195,11 @@ func verifyV2Signatures(tx *types.Transaction, getZCRingOutputs ZCRingOutputsFn)
|
||||||
|
|
||||||
ringMembers, err := getZCRingOutputs(offsets)
|
ringMembers, err := getZCRingOutputs(offsets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: failed to fetch ZC ring outputs for input %d", i), err)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: failed to fetch ZC ring outputs for input %d", i), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ringMembers) != zc.ringSize {
|
if len(ringMembers) != zc.ringSize {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: input %d: ring size %d from chain != %d from sig", i, len(ringMembers), zc.ringSize), nil)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: input %d: ring size %d from chain != %d from sig", i, len(ringMembers), zc.ringSize), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build flat ring: [stealth(32) | commitment(32) | blinded_asset_id(32)] per entry.
|
// Build flat ring: [stealth(32) | commitment(32) | blinded_asset_id(32)] per entry.
|
||||||
|
|
@ -219,7 +218,7 @@ func verifyV2Signatures(tx *types.Transaction, getZCRingOutputs ZCRingOutputsFn)
|
||||||
[32]byte(zcIn.KeyImage),
|
[32]byte(zcIn.KeyImage),
|
||||||
zc.clsagFlatSig,
|
zc.clsagFlatSig,
|
||||||
) {
|
) {
|
||||||
return coreerr.E("verifyV2Signatures", fmt.Sprintf("consensus: CLSAG GGX verification failed for input %d", i), nil)
|
return coreerr.E("verifyV2Signatures", core.Sprintf("consensus: CLSAG GGX verification failed for input %d", i), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,7 +272,7 @@ func verifyBGEProofs(tx *types.Transaction, sigEntries []v2SigEntry,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(proofs.bgeProofs) != len(outputAssetIDs) {
|
if len(proofs.bgeProofs) != len(outputAssetIDs) {
|
||||||
return coreerr.E("verifyBGEProofs", fmt.Sprintf("consensus: BGE proof count %d != Zarcanum output count %d", len(proofs.bgeProofs), len(outputAssetIDs)), nil)
|
return coreerr.E("verifyBGEProofs", core.Sprintf("consensus: BGE proof count %d != Zarcanum output count %d", len(proofs.bgeProofs), len(outputAssetIDs)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect pseudo-out asset IDs from ZC signatures and expand to full points.
|
// Collect pseudo-out asset IDs from ZC signatures and expand to full points.
|
||||||
|
|
@ -289,7 +288,7 @@ func verifyBGEProofs(tx *types.Transaction, sigEntries []v2SigEntry,
|
||||||
for i, p := range pseudoOutAssetIDs {
|
for i, p := range pseudoOutAssetIDs {
|
||||||
full, err := crypto.PointMul8(p)
|
full, err := crypto.PointMul8(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("verifyBGEProofs", fmt.Sprintf("consensus: mul8 pseudo-out asset ID %d", i), err)
|
return coreerr.E("verifyBGEProofs", core.Sprintf("consensus: mul8 pseudo-out asset ID %d", i), err)
|
||||||
}
|
}
|
||||||
mul8PseudoOuts[i] = full
|
mul8PseudoOuts[i] = full
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +299,7 @@ func verifyBGEProofs(tx *types.Transaction, sigEntries []v2SigEntry,
|
||||||
// mul8 the output's blinded asset ID.
|
// mul8 the output's blinded asset ID.
|
||||||
mul8Out, err := crypto.PointMul8(outAssetID)
|
mul8Out, err := crypto.PointMul8(outAssetID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("verifyBGEProofs", fmt.Sprintf("consensus: mul8 output asset ID %d", j), err)
|
return coreerr.E("verifyBGEProofs", core.Sprintf("consensus: mul8 output asset ID %d", j), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ring[i] = mul8(pseudo_out_i) - mul8(output_j)
|
// ring[i] = mul8(pseudo_out_i) - mul8(output_j)
|
||||||
|
|
@ -308,13 +307,13 @@ func verifyBGEProofs(tx *types.Transaction, sigEntries []v2SigEntry,
|
||||||
for i, mul8Pseudo := range mul8PseudoOuts {
|
for i, mul8Pseudo := range mul8PseudoOuts {
|
||||||
diff, err := crypto.PointSub(mul8Pseudo, mul8Out)
|
diff, err := crypto.PointSub(mul8Pseudo, mul8Out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("verifyBGEProofs", fmt.Sprintf("consensus: BGE ring[%d][%d] sub", j, i), err)
|
return coreerr.E("verifyBGEProofs", core.Sprintf("consensus: BGE ring[%d][%d] sub", j, i), err)
|
||||||
}
|
}
|
||||||
ring[i] = diff
|
ring[i] = diff
|
||||||
}
|
}
|
||||||
|
|
||||||
if !crypto.VerifyBGE(context, ring, proofs.bgeProofs[j]) {
|
if !crypto.VerifyBGE(context, ring, proofs.bgeProofs[j]) {
|
||||||
return coreerr.E("verifyBGEProofs", fmt.Sprintf("consensus: BGE proof verification failed for output %d", j), nil)
|
return coreerr.E("verifyBGEProofs", core.Sprintf("consensus: BGE proof verification failed for output %d", j), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ package crypto
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ func GenerateKeys() (pub [32]byte, sec [32]byte, err error) {
|
||||||
(*C.uint8_t)(unsafe.Pointer(&sec[0])),
|
(*C.uint8_t)(unsafe.Pointer(&sec[0])),
|
||||||
)
|
)
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
err = coreerr.E("GenerateKeys", fmt.Sprintf("generate_keys failed (rc=%d)", rc), nil)
|
err = coreerr.E("GenerateKeys", core.Sprintf("generate_keys failed (rc=%d)", rc), nil)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +34,7 @@ func SecretToPublic(sec [32]byte) ([32]byte, error) {
|
||||||
(*C.uint8_t)(unsafe.Pointer(&pub[0])),
|
(*C.uint8_t)(unsafe.Pointer(&pub[0])),
|
||||||
)
|
)
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
return pub, coreerr.E("SecretToPublic", fmt.Sprintf("secret_to_public failed (rc=%d)", rc), nil)
|
return pub, coreerr.E("SecretToPublic", core.Sprintf("secret_to_public failed (rc=%d)", rc), nil)
|
||||||
}
|
}
|
||||||
return pub, nil
|
return pub, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ package crypto
|
||||||
// #include "bridge.h"
|
// #include "bridge.h"
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ func RandomXHash(key, input []byte) ([32]byte, error) {
|
||||||
(*C.uint8_t)(unsafe.Pointer(&output[0])),
|
(*C.uint8_t)(unsafe.Pointer(&output[0])),
|
||||||
)
|
)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return output, coreerr.E("RandomXHash", fmt.Sprintf("RandomX hash failed with code %d", ret), nil)
|
return output, coreerr.E("RandomXHash", core.Sprintf("RandomX hash failed with code %d", ret), nil)
|
||||||
}
|
}
|
||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
go.mod
3
go.mod
|
|
@ -3,6 +3,7 @@ module dappco.re/go/core/blockchain
|
||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
dappco.re/go/core v0.8.0-alpha.1
|
||||||
dappco.re/go/core/cli v0.3.1
|
dappco.re/go/core/cli v0.3.1
|
||||||
dappco.re/go/core/io v0.2.0
|
dappco.re/go/core/io v0.2.0
|
||||||
dappco.re/go/core/log v0.1.0
|
dappco.re/go/core/log v0.1.0
|
||||||
|
|
@ -63,7 +64,7 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
dappco.re/go/core => forge.lthn.ai/core/go v0.5.0
|
dappco.re/go/core => forge.lthn.ai/core/go v0.8.0-alpha.1
|
||||||
dappco.re/go/core/cli => forge.lthn.ai/core/cli v0.3.1
|
dappco.re/go/core/cli => forge.lthn.ai/core/cli v0.3.1
|
||||||
dappco.re/go/core/crypt => forge.lthn.ai/core/go-crypt v0.1.7
|
dappco.re/go/core/crypt => forge.lthn.ai/core/go-crypt v0.1.7
|
||||||
dappco.re/go/core/i18n => forge.lthn.ai/core/go-i18n v0.1.4
|
dappco.re/go/core/i18n => forge.lthn.ai/core/go-i18n v0.1.4
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -2,6 +2,8 @@ forge.lthn.ai/core/cli v0.3.1 h1:ZpHhaDrdbaV98JDxj/f0E5nytYk9tTMRu3qohGyK4M0=
|
||||||
forge.lthn.ai/core/cli v0.3.1/go.mod h1:28cOl9eK0H033Otkjrv9f/QCmtHcJl+IIx4om8JskOg=
|
forge.lthn.ai/core/cli v0.3.1/go.mod h1:28cOl9eK0H033Otkjrv9f/QCmtHcJl+IIx4om8JskOg=
|
||||||
forge.lthn.ai/core/go v0.3.1 h1:5FMTsUhLcxSr07F9q3uG0Goy4zq4eLivoqi8shSY4UM=
|
forge.lthn.ai/core/go v0.3.1 h1:5FMTsUhLcxSr07F9q3uG0Goy4zq4eLivoqi8shSY4UM=
|
||||||
forge.lthn.ai/core/go v0.3.1/go.mod h1:gE6c8h+PJ2287qNhVUJ5SOe1kopEwHEquvinstpuyJc=
|
forge.lthn.ai/core/go v0.3.1/go.mod h1:gE6c8h+PJ2287qNhVUJ5SOe1kopEwHEquvinstpuyJc=
|
||||||
|
forge.lthn.ai/core/go v0.8.0-alpha.1 h1:dybLUTR9HMqtT5lxolAUaF1c+j/vGPIDMyiMygyGlq8=
|
||||||
|
forge.lthn.ai/core/go v0.8.0-alpha.1/go.mod h1:f2/tBZ3+3IqDrg2F5F598llv0nmb/4gJVCFzM5geE4A=
|
||||||
forge.lthn.ai/core/go-crypt v0.1.6 h1:jB7L/28S1NR+91u3GcOYuKfBLzPhhBUY1fRe6WkGVns=
|
forge.lthn.ai/core/go-crypt v0.1.6 h1:jB7L/28S1NR+91u3GcOYuKfBLzPhhBUY1fRe6WkGVns=
|
||||||
forge.lthn.ai/core/go-crypt v0.1.6/go.mod h1:4VZAGqxlbadhSB66sJkdj54/HSJ+bSxVgwWK5kMMYDo=
|
forge.lthn.ai/core/go-crypt v0.1.6/go.mod h1:4VZAGqxlbadhSB66sJkdj54/HSJ+bSxVgwWK5kMMYDo=
|
||||||
forge.lthn.ai/core/go-i18n v0.1.4 h1:zOHUUJDgRo88/3tj++kN+VELg/buyZ4T2OSdG3HBbLQ=
|
forge.lthn.ai/core/go-i18n v0.1.4 h1:zOHUUJDgRo88/3tj++kN+VELg/buyZ4T2OSdG3HBbLQ=
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/consensus"
|
"dappco.re/go/core/blockchain/consensus"
|
||||||
|
|
@ -141,7 +141,7 @@ func (m *Miner) Start(ctx context.Context) error {
|
||||||
// Parse difficulty.
|
// Parse difficulty.
|
||||||
diff, err := strconv.ParseUint(tmpl.Difficulty, 10, 64)
|
diff, err := strconv.ParseUint(tmpl.Difficulty, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Miner.Start", fmt.Sprintf("mining: invalid difficulty %q", tmpl.Difficulty), err)
|
return coreerr.E("Miner.Start", core.Sprintf("mining: invalid difficulty %q", tmpl.Difficulty), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the block template blob.
|
// Decode the block template blob.
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -21,7 +20,7 @@ func (c *Client) GetLastBlockHeader() (*BlockHeader, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetLastBlockHeader", fmt.Sprintf("getlastblockheader: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetLastBlockHeader", core.Sprintf("getlastblockheader: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return &resp.BlockHeader, nil
|
return &resp.BlockHeader, nil
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +38,7 @@ func (c *Client) GetBlockHeaderByHeight(height uint64) (*BlockHeader, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetBlockHeaderByHeight", fmt.Sprintf("getblockheaderbyheight: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetBlockHeaderByHeight", core.Sprintf("getblockheaderbyheight: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return &resp.BlockHeader, nil
|
return &resp.BlockHeader, nil
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +56,7 @@ func (c *Client) GetBlockHeaderByHash(hash string) (*BlockHeader, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetBlockHeaderByHash", fmt.Sprintf("getblockheaderbyhash: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetBlockHeaderByHash", core.Sprintf("getblockheaderbyhash: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return &resp.BlockHeader, nil
|
return &resp.BlockHeader, nil
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +76,7 @@ func (c *Client) GetBlocksDetails(heightStart, count uint64) ([]BlockDetails, er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetBlocksDetails", fmt.Sprintf("get_blocks_details: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetBlocksDetails", core.Sprintf("get_blocks_details: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return resp.Blocks, nil
|
return resp.Blocks, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ var testBlockHeaderJSON = `{
|
||||||
func blockHeaderResponse() jsonRPCResponse {
|
func blockHeaderResponse() jsonRPCResponse {
|
||||||
return jsonRPCResponse{
|
return jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{"block_header":` + testBlockHeaderJSON + `,"status":"OK"}`),
|
Result: rawJSON(`{"block_header":` + testBlockHeaderJSON + `,"status":"OK"}`),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,8 +96,8 @@ func TestGetBlocksDetails_Good(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{
|
Result: rawJSON(`{
|
||||||
"blocks": [{
|
"blocks": [{
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"timestamp": 1770897600,
|
"timestamp": 1770897600,
|
||||||
|
|
@ -134,7 +134,7 @@ func TestGetBlockHeaderByHeight_Bad_TooBig(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Error: &jsonRPCError{Code: -2, Message: "TOO_BIG_HEIGHT"},
|
Error: &jsonRPCError{Code: -2, Message: "TOO_BIG_HEIGHT"},
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,12 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -38,7 +37,7 @@ func NewClientWithHTTP(daemonURL string, httpClient *http.Client) *Client {
|
||||||
// Fall through with raw URL.
|
// Fall through with raw URL.
|
||||||
return &Client{url: daemonURL + "/json_rpc", baseURL: daemonURL, httpClient: httpClient}
|
return &Client{url: daemonURL + "/json_rpc", baseURL: daemonURL, httpClient: httpClient}
|
||||||
}
|
}
|
||||||
baseURL := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
|
baseURL := core.Sprintf("%s://%s", u.Scheme, u.Host)
|
||||||
if u.Path == "" || u.Path == "/" {
|
if u.Path == "" || u.Path == "/" {
|
||||||
u.Path = "/json_rpc"
|
u.Path = "/json_rpc"
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ type RPCError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *RPCError) Error() string {
|
func (e *RPCError) Error() string {
|
||||||
return fmt.Sprintf("rpc error %d: %s", e.Code, e.Message)
|
return core.Sprintf("rpc error %d: %s", e.Code, e.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON-RPC 2.0 envelope types.
|
// JSON-RPC 2.0 envelope types.
|
||||||
|
|
@ -68,10 +67,10 @@ type jsonRPCRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonRPCResponse struct {
|
type jsonRPCResponse struct {
|
||||||
JSONRPC string `json:"jsonrpc"`
|
JSONRPC string `json:"jsonrpc"`
|
||||||
ID json.RawMessage `json:"id"`
|
ID rawJSON `json:"id"`
|
||||||
Result json.RawMessage `json:"result"`
|
Result rawJSON `json:"result"`
|
||||||
Error *jsonRPCError `json:"error,omitempty"`
|
Error *jsonRPCError `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonRPCError struct {
|
type jsonRPCError struct {
|
||||||
|
|
@ -79,26 +78,37 @@ type jsonRPCError struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rawJSON []byte
|
||||||
|
|
||||||
|
func (r *rawJSON) UnmarshalJSON(data []byte) error {
|
||||||
|
*r = append((*r)[:0], data...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rawJSON) MarshalJSON() ([]byte, error) {
|
||||||
|
if r == nil {
|
||||||
|
return []byte("null"), nil
|
||||||
|
}
|
||||||
|
return []byte(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
// call makes a JSON-RPC 2.0 call to /json_rpc.
|
// call makes a JSON-RPC 2.0 call to /json_rpc.
|
||||||
func (c *Client) call(method string, params any, result any) error {
|
func (c *Client) call(method string, params any, result any) error {
|
||||||
reqBody, err := json.Marshal(jsonRPCRequest{
|
reqBody := core.JSONMarshalString(jsonRPCRequest{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: "0",
|
ID: "0",
|
||||||
Method: method,
|
Method: method,
|
||||||
Params: params,
|
Params: params,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return coreerr.E("Client.call", "marshal request", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.httpClient.Post(c.url, "application/json", bytes.NewReader(reqBody))
|
resp, err := c.httpClient.Post(c.url, "application/json", bytes.NewReader([]byte(reqBody)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Client.call", fmt.Sprintf("post %s", method), err)
|
return coreerr.E("Client.call", core.Sprintf("post %s", method), err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return coreerr.E("Client.call", fmt.Sprintf("http %d from %s", resp.StatusCode, method), nil)
|
return coreerr.E("Client.call", core.Sprintf("http %d from %s", resp.StatusCode, method), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
|
@ -107,8 +117,8 @@ func (c *Client) call(method string, params any, result any) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var rpcResp jsonRPCResponse
|
var rpcResp jsonRPCResponse
|
||||||
if err := json.Unmarshal(body, &rpcResp); err != nil {
|
if r := core.JSONUnmarshalString(string(body), &rpcResp); !r.OK {
|
||||||
return coreerr.E("Client.call", "unmarshal response", err)
|
return coreerr.E("Client.call", "unmarshal response", r.Value.(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
if rpcResp.Error != nil {
|
if rpcResp.Error != nil {
|
||||||
|
|
@ -116,8 +126,8 @@ func (c *Client) call(method string, params any, result any) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if result != nil && len(rpcResp.Result) > 0 {
|
if result != nil && len(rpcResp.Result) > 0 {
|
||||||
if err := json.Unmarshal(rpcResp.Result, result); err != nil {
|
if r := core.JSONUnmarshalString(string(rpcResp.Result), result); !r.OK {
|
||||||
return coreerr.E("Client.call", "unmarshal result", err)
|
return coreerr.E("Client.call", "unmarshal result", r.Value.(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -125,20 +135,17 @@ func (c *Client) call(method string, params any, result any) error {
|
||||||
|
|
||||||
// legacyCall makes a plain JSON POST to a legacy URI path (e.g. /getheight).
|
// legacyCall makes a plain JSON POST to a legacy URI path (e.g. /getheight).
|
||||||
func (c *Client) legacyCall(path string, params any, result any) error {
|
func (c *Client) legacyCall(path string, params any, result any) error {
|
||||||
reqBody, err := json.Marshal(params)
|
reqBody := core.JSONMarshalString(params)
|
||||||
if err != nil {
|
|
||||||
return coreerr.E("Client.legacyCall", "marshal request", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
url := c.baseURL + path
|
url := c.baseURL + path
|
||||||
resp, err := c.httpClient.Post(url, "application/json", bytes.NewReader(reqBody))
|
resp, err := c.httpClient.Post(url, "application/json", bytes.NewReader([]byte(reqBody)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Client.legacyCall", fmt.Sprintf("post %s", path), err)
|
return coreerr.E("Client.legacyCall", core.Sprintf("post %s", path), err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return coreerr.E("Client.legacyCall", fmt.Sprintf("http %d from %s", resp.StatusCode, path), nil)
|
return coreerr.E("Client.legacyCall", core.Sprintf("http %d from %s", resp.StatusCode, path), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
|
@ -147,8 +154,8 @@ func (c *Client) legacyCall(path string, params any, result any) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if result != nil {
|
if result != nil {
|
||||||
if err := json.Unmarshal(body, result); err != nil {
|
if r := core.JSONUnmarshalString(string(body), result); !r.OK {
|
||||||
return coreerr.E("Client.legacyCall", "unmarshal response", err)
|
return coreerr.E("Client.legacyCall", "unmarshal response", r.Value.(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ func TestClient_Good_JSONRPCCall(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{"count":6300,"status":"OK"}`),
|
Result: rawJSON(`{"count":6300,"status":"OK"}`),
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
@ -88,7 +88,7 @@ func TestClient_Bad_RPCError(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Error: &jsonRPCError{
|
Error: &jsonRPCError{
|
||||||
Code: -2,
|
Code: -2,
|
||||||
Message: "TOO_BIG_HEIGHT",
|
Message: "TOO_BIG_HEIGHT",
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -25,7 +24,7 @@ func (c *Client) GetInfo() (*DaemonInfo, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetInfo", fmt.Sprintf("getinfo: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetInfo", core.Sprintf("getinfo: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return &resp.DaemonInfo, nil
|
return &resp.DaemonInfo, nil
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +40,7 @@ func (c *Client) GetHeight() (uint64, error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return 0, coreerr.E("Client.GetHeight", fmt.Sprintf("getheight: status %q", resp.Status), nil)
|
return 0, coreerr.E("Client.GetHeight", core.Sprintf("getheight: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return resp.Height, nil
|
return resp.Height, nil
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ func (c *Client) GetBlockCount() (uint64, error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return 0, coreerr.E("Client.GetBlockCount", fmt.Sprintf("getblockcount: status %q", resp.Status), nil)
|
return 0, coreerr.E("Client.GetBlockCount", core.Sprintf("getblockcount: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return resp.Count, nil
|
return resp.Count, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ func TestGetInfo_Good(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{
|
Result: rawJSON(`{
|
||||||
"height": 6300,
|
"height": 6300,
|
||||||
"tx_count": 12345,
|
"tx_count": 12345,
|
||||||
"tx_pool_size": 3,
|
"tx_pool_size": 3,
|
||||||
|
|
@ -83,8 +83,8 @@ func TestGetBlockCount_Good(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{"count":6301,"status":"OK"}`),
|
Result: rawJSON(`{"count":6301,"status":"OK"}`),
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -24,7 +23,7 @@ func (c *Client) SubmitBlock(hexBlob string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return coreerr.E("Client.SubmitBlock", fmt.Sprintf("submitblock: status %q", resp.Status), nil)
|
return coreerr.E("Client.SubmitBlock", core.Sprintf("submitblock: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +50,7 @@ func (c *Client) GetBlockTemplate(walletAddr string) (*BlockTemplateResponse, er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetBlockTemplate", fmt.Sprintf("getblocktemplate: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetBlockTemplate", core.Sprintf("getblocktemplate: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ func TestSubmitBlock_Good(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{"status":"OK"}`),
|
Result: rawJSON(`{"status":"OK"}`),
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
@ -49,7 +49,7 @@ func TestSubmitBlock_Bad_Rejected(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Error: &jsonRPCError{Code: -7, Message: "BLOCK_NOT_ACCEPTED"},
|
Error: &jsonRPCError{Code: -7, Message: "BLOCK_NOT_ACCEPTED"},
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
|
@ -86,8 +86,8 @@ func TestGetBlockTemplate_Good(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{
|
Result: rawJSON(`{
|
||||||
"difficulty": "42",
|
"difficulty": "42",
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"blocktemplate_blob": "0100000000000000000000000000",
|
"blocktemplate_blob": "0100000000000000000000000000",
|
||||||
|
|
@ -122,8 +122,8 @@ func TestGetBlockTemplate_Bad_Status(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{"status":"BUSY"}`),
|
Result: rawJSON(`{"status":"BUSY"}`),
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -24,7 +23,7 @@ func (c *Client) GetTxDetails(txHash string) (*TxInfo, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetTxDetails", fmt.Sprintf("get_tx_details: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetTxDetails", core.Sprintf("get_tx_details: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return &resp.TxInfo, nil
|
return &resp.TxInfo, nil
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +44,7 @@ func (c *Client) GetTransactions(hashes []string) (txsHex []string, missed []str
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, nil, coreerr.E("Client.GetTransactions", fmt.Sprintf("gettransactions: status %q", resp.Status), nil)
|
return nil, nil, coreerr.E("Client.GetTransactions", core.Sprintf("gettransactions: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return resp.TxsAsHex, resp.MissedTx, nil
|
return resp.TxsAsHex, resp.MissedTx, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ func TestGetTxDetails_Good(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Result: json.RawMessage(`{
|
Result: rawJSON(`{
|
||||||
"status": "OK",
|
"status": "OK",
|
||||||
"tx_info": {
|
"tx_info": {
|
||||||
"id": "a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8",
|
"id": "a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8",
|
||||||
|
|
@ -55,7 +55,7 @@ func TestGetTxDetails_Bad_NotFound(t *testing.T) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(jsonRPCResponse{
|
json.NewEncoder(w).Encode(jsonRPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: json.RawMessage(`"0"`),
|
ID: rawJSON(`"0"`),
|
||||||
Error: &jsonRPCError{Code: -14, Message: "NOT_FOUND"},
|
Error: &jsonRPCError{Code: -14, Message: "NOT_FOUND"},
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,9 @@
|
||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"dappco.re/go/core"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
"encoding/hex"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandomOutputEntry is a decoy output returned by getrandom_outs.
|
// RandomOutputEntry is a decoy output returned by getrandom_outs.
|
||||||
|
|
@ -35,7 +34,7 @@ func (c *Client) GetRandomOutputs(amount uint64, count int) ([]RandomOutputEntry
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return nil, coreerr.E("Client.GetRandomOutputs", fmt.Sprintf("getrandom_outs: status %q", resp.Status), nil)
|
return nil, coreerr.E("Client.GetRandomOutputs", core.Sprintf("getrandom_outs: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return resp.Outs, nil
|
return resp.Outs, nil
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +54,7 @@ func (c *Client) SendRawTransaction(txBlob []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if resp.Status != "OK" {
|
if resp.Status != "OK" {
|
||||||
return coreerr.E("Client.SendRawTransaction", fmt.Sprintf("sendrawtransaction: status %q", resp.Status), nil)
|
return coreerr.E("Client.SendRawTransaction", core.Sprintf("sendrawtransaction: status %q", resp.Status), nil)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/chain"
|
"dappco.re/go/core/blockchain/chain"
|
||||||
|
|
@ -56,7 +56,7 @@ func syncLoop(ctx context.Context, c *chain.Chain, cfg *config.ChainConfig, fork
|
||||||
func syncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConfig, opts chain.SyncOptions, seed string) error {
|
func syncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConfig, opts chain.SyncOptions, seed string) error {
|
||||||
conn, err := net.DialTimeout("tcp", seed, 10*time.Second)
|
conn, err := net.DialTimeout("tcp", seed, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("syncOnce", fmt.Sprintf("dial %s", seed), err)
|
return coreerr.E("syncOnce", core.Sprintf("dial %s", seed), err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ func syncOnce(ctx context.Context, c *chain.Chain, cfg *config.ChainConfig, opts
|
||||||
return coreerr.E("syncOnce", "read handshake", err)
|
return coreerr.E("syncOnce", "read handshake", err)
|
||||||
}
|
}
|
||||||
if hdr.Command != uint32(p2p.CommandHandshake) {
|
if hdr.Command != uint32(p2p.CommandHandshake) {
|
||||||
return coreerr.E("syncOnce", fmt.Sprintf("unexpected command %d", hdr.Command), nil)
|
return coreerr.E("syncOnce", core.Sprintf("unexpected command %d", hdr.Command), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp p2p.HandshakeResponse
|
var resp p2p.HandshakeResponse
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,9 @@
|
||||||
package tui
|
package tui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
cli "dappco.re/go/core/cli/pkg/cli"
|
cli "dappco.re/go/core/cli/pkg/cli"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
|
|
@ -215,10 +214,10 @@ func (m *ExplorerModel) viewBlockList() string {
|
||||||
return " no blocks \u2014 chain is empty"
|
return " no blocks \u2014 chain is empty"
|
||||||
}
|
}
|
||||||
|
|
||||||
var b strings.Builder
|
b := core.NewBuilder()
|
||||||
|
|
||||||
// Header row.
|
// Header row.
|
||||||
header := fmt.Sprintf(" %-8s %-18s %5s %12s %12s",
|
header := core.Sprintf(" %-8s %-18s %5s %12s %12s",
|
||||||
"Height", "Hash", "Txs", "Difficulty", "Age")
|
"Height", "Hash", "Txs", "Difficulty", "Age")
|
||||||
b.WriteString(header)
|
b.WriteString(header)
|
||||||
b.WriteByte('\n')
|
b.WriteByte('\n')
|
||||||
|
|
@ -240,10 +239,10 @@ func (m *ExplorerModel) viewBlockList() string {
|
||||||
prefix = "> "
|
prefix = "> "
|
||||||
}
|
}
|
||||||
|
|
||||||
hashShort := fmt.Sprintf("%x", row.Hash[:4]) + "..."
|
hashShort := core.Concat(core.Sprintf("%x", row.Hash[:4]), "...")
|
||||||
age := formatAge(time.Unix(int64(row.Timestamp), 0))
|
age := formatAge(time.Unix(int64(row.Timestamp), 0))
|
||||||
|
|
||||||
line := fmt.Sprintf("%s%-8d %-18s %5d %12s %12s",
|
line := core.Sprintf("%s%-8d %-18s %5d %12s %12s",
|
||||||
prefix, row.Height, hashShort, row.TxCount,
|
prefix, row.Height, hashShort, row.TxCount,
|
||||||
formatDifficulty(row.Difficulty), age)
|
formatDifficulty(row.Difficulty), age)
|
||||||
|
|
||||||
|
|
@ -264,17 +263,17 @@ func (m *ExplorerModel) viewBlockDetail() string {
|
||||||
return " no block selected"
|
return " no block selected"
|
||||||
}
|
}
|
||||||
|
|
||||||
var b strings.Builder
|
b := core.NewBuilder()
|
||||||
meta := m.blockMeta
|
meta := m.blockMeta
|
||||||
blk := m.block
|
blk := m.block
|
||||||
|
|
||||||
b.WriteString(fmt.Sprintf(" Block %d\n", meta.Height))
|
b.WriteString(core.Sprintf(" Block %d\n", meta.Height))
|
||||||
b.WriteString(fmt.Sprintf(" Hash: %x\n", meta.Hash))
|
b.WriteString(core.Sprintf(" Hash: %x\n", meta.Hash))
|
||||||
b.WriteString(fmt.Sprintf(" Timestamp: %s\n", time.Unix(int64(meta.Timestamp), 0).UTC().Format(time.RFC3339)))
|
b.WriteString(core.Sprintf(" Timestamp: %s\n", time.Unix(int64(meta.Timestamp), 0).UTC().Format(time.RFC3339)))
|
||||||
b.WriteString(fmt.Sprintf(" Difficulty: %s\n", formatDifficulty(meta.Difficulty)))
|
b.WriteString(core.Sprintf(" Difficulty: %s\n", formatDifficulty(meta.Difficulty)))
|
||||||
b.WriteString(fmt.Sprintf(" Version: %d.%d\n", blk.MajorVersion, blk.MinorVersion))
|
b.WriteString(core.Sprintf(" Version: %d.%d\n", blk.MajorVersion, blk.MinorVersion))
|
||||||
b.WriteString(fmt.Sprintf(" Nonce: %d\n", blk.Nonce))
|
b.WriteString(core.Sprintf(" Nonce: %d\n", blk.Nonce))
|
||||||
b.WriteString(fmt.Sprintf(" Txs: %d\n\n", len(blk.TxHashes)))
|
b.WriteString(core.Sprintf(" Txs: %d\n\n", len(blk.TxHashes)))
|
||||||
|
|
||||||
if len(blk.TxHashes) == 0 {
|
if len(blk.TxHashes) == 0 {
|
||||||
b.WriteString(" (coinbase only)")
|
b.WriteString(" (coinbase only)")
|
||||||
|
|
@ -285,7 +284,7 @@ func (m *ExplorerModel) viewBlockDetail() string {
|
||||||
if i == m.txCursor {
|
if i == m.txCursor {
|
||||||
prefix = "> "
|
prefix = "> "
|
||||||
}
|
}
|
||||||
b.WriteString(fmt.Sprintf(" %s%x\n", prefix, txHash[:8]))
|
b.WriteString(core.Sprintf(" %s%x\n", prefix, txHash[:8]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,25 +296,25 @@ func (m *ExplorerModel) viewTxDetail() string {
|
||||||
return " no transaction selected"
|
return " no transaction selected"
|
||||||
}
|
}
|
||||||
|
|
||||||
var b strings.Builder
|
b := core.NewBuilder()
|
||||||
tx := m.tx
|
tx := m.tx
|
||||||
|
|
||||||
b.WriteString(" Transaction\n")
|
b.WriteString(" Transaction\n")
|
||||||
b.WriteString(fmt.Sprintf(" Hash: %x\n", m.txHash))
|
b.WriteString(core.Sprintf(" Hash: %x\n", m.txHash))
|
||||||
b.WriteString(fmt.Sprintf(" Version: %d\n", tx.Version))
|
b.WriteString(core.Sprintf(" Version: %d\n", tx.Version))
|
||||||
b.WriteString(fmt.Sprintf(" Inputs: %d\n", len(tx.Vin)))
|
b.WriteString(core.Sprintf(" Inputs: %d\n", len(tx.Vin)))
|
||||||
b.WriteString(fmt.Sprintf(" Outputs: %d\n\n", len(tx.Vout)))
|
b.WriteString(core.Sprintf(" Outputs: %d\n\n", len(tx.Vout)))
|
||||||
|
|
||||||
if len(tx.Vin) > 0 {
|
if len(tx.Vin) > 0 {
|
||||||
b.WriteString(" Inputs:\n")
|
b.WriteString(" Inputs:\n")
|
||||||
for i, in := range tx.Vin {
|
for i, in := range tx.Vin {
|
||||||
switch v := in.(type) {
|
switch v := in.(type) {
|
||||||
case types.TxInputGenesis:
|
case types.TxInputGenesis:
|
||||||
b.WriteString(fmt.Sprintf(" [%d] coinbase height=%d\n", i, v.Height))
|
b.WriteString(core.Sprintf(" [%d] coinbase height=%d\n", i, v.Height))
|
||||||
case types.TxInputToKey:
|
case types.TxInputToKey:
|
||||||
b.WriteString(fmt.Sprintf(" [%d] to_key amount=%d key_image=%x\n", i, v.Amount, v.KeyImage[:4]))
|
b.WriteString(core.Sprintf(" [%d] to_key amount=%d key_image=%x\n", i, v.Amount, v.KeyImage[:4]))
|
||||||
default:
|
default:
|
||||||
b.WriteString(fmt.Sprintf(" [%d] %T\n", i, v))
|
b.WriteString(core.Sprintf(" [%d] %T\n", i, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -326,14 +325,14 @@ func (m *ExplorerModel) viewTxDetail() string {
|
||||||
switch v := out.(type) {
|
switch v := out.(type) {
|
||||||
case types.TxOutputBare:
|
case types.TxOutputBare:
|
||||||
if toKey, ok := v.Target.(types.TxOutToKey); ok {
|
if toKey, ok := v.Target.(types.TxOutToKey); ok {
|
||||||
b.WriteString(fmt.Sprintf(" [%d] bare amount=%d key=%x\n", i, v.Amount, toKey.Key[:4]))
|
b.WriteString(core.Sprintf(" [%d] bare amount=%d key=%x\n", i, v.Amount, toKey.Key[:4]))
|
||||||
} else {
|
} else {
|
||||||
b.WriteString(fmt.Sprintf(" [%d] bare amount=%d target=%T\n", i, v.Amount, v.Target))
|
b.WriteString(core.Sprintf(" [%d] bare amount=%d target=%T\n", i, v.Amount, v.Target))
|
||||||
}
|
}
|
||||||
case types.TxOutputZarcanum:
|
case types.TxOutputZarcanum:
|
||||||
b.WriteString(fmt.Sprintf(" [%d] zarcanum stealth=%x\n", i, v.StealthAddress[:4]))
|
b.WriteString(core.Sprintf(" [%d] zarcanum stealth=%x\n", i, v.StealthAddress[:4]))
|
||||||
default:
|
default:
|
||||||
b.WriteString(fmt.Sprintf(" [%d] %T\n", i, v))
|
b.WriteString(core.Sprintf(" [%d] %T\n", i, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package tui
|
package tui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
cli "dappco.re/go/core/cli/pkg/cli"
|
cli "dappco.re/go/core/cli/pkg/cli"
|
||||||
|
|
@ -44,7 +43,7 @@ func (m *KeyHintsModel) Update(msg tea.Msg) (cli.FrameModel, tea.Cmd) {
|
||||||
// View renders a single-line hint bar separated by vertical bars.
|
// View renders a single-line hint bar separated by vertical bars.
|
||||||
// The output is truncated to width if it would overflow.
|
// The output is truncated to width if it would overflow.
|
||||||
func (m *KeyHintsModel) View(width, height int) string {
|
func (m *KeyHintsModel) View(width, height int) string {
|
||||||
line := " " + strings.Join(m.hints, " \u2502 ")
|
line := " " + core.Join(" \u2502 ", m.hints...)
|
||||||
if len(line) > width && width > 0 {
|
if len(line) > width && width > 0 {
|
||||||
line = line[:width]
|
line = line[:width]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
package tui
|
package tui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
||||||
cli "dappco.re/go/core/cli/pkg/cli"
|
cli "dappco.re/go/core/cli/pkg/cli"
|
||||||
|
|
@ -53,7 +53,7 @@ func (m *StatusModel) View(width, height int) string {
|
||||||
line = " height 0 | syncing..."
|
line = " height 0 | syncing..."
|
||||||
} else {
|
} else {
|
||||||
s := m.status
|
s := m.status
|
||||||
line = fmt.Sprintf(" height %d | sync %.1f%% | diff %s | %d peers | tip %s",
|
line = core.Sprintf(" height %d | sync %.1f%% | diff %s | %d peers | tip %s",
|
||||||
s.Height, s.SyncPct, formatDifficulty(s.Difficulty), s.PeerCount, formatAge(s.TipTime))
|
s.Height, s.SyncPct, formatDifficulty(s.Difficulty), s.PeerCount, formatAge(s.TipTime))
|
||||||
}
|
}
|
||||||
if len(line) > width && width > 0 {
|
if len(line) > width && width > 0 {
|
||||||
|
|
@ -70,13 +70,13 @@ func formatAge(t time.Time) string {
|
||||||
d := time.Since(t)
|
d := time.Since(t)
|
||||||
switch {
|
switch {
|
||||||
case d < time.Minute:
|
case d < time.Minute:
|
||||||
return fmt.Sprintf("%ds ago", int(d.Seconds()))
|
return core.Sprintf("%ds ago", int(d.Seconds()))
|
||||||
case d < time.Hour:
|
case d < time.Hour:
|
||||||
return fmt.Sprintf("%dm ago", int(d.Minutes()))
|
return core.Sprintf("%dm ago", int(d.Minutes()))
|
||||||
case d < 24*time.Hour:
|
case d < 24*time.Hour:
|
||||||
return fmt.Sprintf("%dh ago", int(d.Hours()))
|
return core.Sprintf("%dh ago", int(d.Hours()))
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%dd ago", int(d.Hours()/24))
|
return core.Sprintf("%dd ago", int(d.Hours()/24))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,12 +84,12 @@ func formatAge(t time.Time) string {
|
||||||
func formatDifficulty(d uint64) string {
|
func formatDifficulty(d uint64) string {
|
||||||
switch {
|
switch {
|
||||||
case d >= 1_000_000_000:
|
case d >= 1_000_000_000:
|
||||||
return fmt.Sprintf("%.1fG", float64(d)/1_000_000_000)
|
return core.Sprintf("%.1fG", float64(d)/1_000_000_000)
|
||||||
case d >= 1_000_000:
|
case d >= 1_000_000:
|
||||||
return fmt.Sprintf("%.1fM", float64(d)/1_000_000)
|
return core.Sprintf("%.1fM", float64(d)/1_000_000)
|
||||||
case d >= 1_000:
|
case d >= 1_000:
|
||||||
return fmt.Sprintf("%.1fK", float64(d)/1_000)
|
return core.Sprintf("%.1fK", float64(d)/1_000)
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%d", d)
|
return core.Sprintf("%d", d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
@ -99,7 +99,7 @@ func DecodeAddress(s string) (*Address, uint64, error) {
|
||||||
// After the prefix we need exactly 32+32+1+4 = 69 bytes.
|
// After the prefix we need exactly 32+32+1+4 = 69 bytes.
|
||||||
remaining := raw[prefixLen:]
|
remaining := raw[prefixLen:]
|
||||||
if len(remaining) != 69 {
|
if len(remaining) != 69 {
|
||||||
return nil, 0, coreerr.E("DecodeAddress", fmt.Sprintf("types: unexpected address data length: want 69 bytes after prefix, got %d", len(remaining)), nil)
|
return nil, 0, coreerr.E("DecodeAddress", core.Sprintf("types: unexpected address data length: want 69 bytes after prefix, got %d", len(remaining)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checksum: Keccak-256 of everything except the last 4 bytes.
|
// Validate checksum: Keccak-256 of everything except the last 4 bytes.
|
||||||
|
|
@ -223,7 +223,7 @@ func base58Decode(s string) ([]byte, error) {
|
||||||
|
|
||||||
// Validate that the last block size maps to a valid byte count.
|
// Validate that the last block size maps to a valid byte count.
|
||||||
if lastBlockChars > 0 && base58ReverseBlockSizes[lastBlockChars] < 0 {
|
if lastBlockChars > 0 && base58ReverseBlockSizes[lastBlockChars] < 0 {
|
||||||
return nil, coreerr.E("base58Decode", fmt.Sprintf("types: invalid base58 string length %d", len(s)), nil)
|
return nil, coreerr.E("base58Decode", core.Sprintf("types: invalid base58 string length %d", len(s)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []byte
|
var result []byte
|
||||||
|
|
@ -258,7 +258,7 @@ func decodeBlock(s string, byteCount int) ([]byte, error) {
|
||||||
for _, c := range []byte(s) {
|
for _, c := range []byte(s) {
|
||||||
idx := base58CharIndex(c)
|
idx := base58CharIndex(c)
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
return nil, coreerr.E("decodeBlock", fmt.Sprintf("types: invalid base58 character %q", c), nil)
|
return nil, coreerr.E("decodeBlock", core.Sprintf("types: invalid base58 character %q", c), nil)
|
||||||
}
|
}
|
||||||
num.Mul(num, base)
|
num.Mul(num, base)
|
||||||
num.Add(num, big.NewInt(int64(idx)))
|
num.Add(num, big.NewInt(int64(idx)))
|
||||||
|
|
@ -267,7 +267,7 @@ func decodeBlock(s string, byteCount int) ([]byte, error) {
|
||||||
// Convert to fixed-size byte array, big-endian.
|
// Convert to fixed-size byte array, big-endian.
|
||||||
raw := num.Bytes()
|
raw := num.Bytes()
|
||||||
if len(raw) > byteCount {
|
if len(raw) > byteCount {
|
||||||
return nil, coreerr.E("decodeBlock", fmt.Sprintf("types: base58 block overflow: decoded %d bytes, expected %d", len(raw), byteCount), nil)
|
return nil, coreerr.E("decodeBlock", core.Sprintf("types: base58 block overflow: decoded %d bytes, expected %d", len(raw), byteCount), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad with leading zeroes if necessary.
|
// Pad with leading zeroes if necessary.
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,9 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"dappco.re/go/core"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
"encoding/hex"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hash is a 256-bit (32-byte) hash value, typically produced by Keccak-256.
|
// Hash is a 256-bit (32-byte) hash value, typically produced by Keccak-256.
|
||||||
|
|
@ -45,7 +44,7 @@ func HashFromHex(s string) (Hash, error) {
|
||||||
return h, coreerr.E("HashFromHex", "types: invalid hex for hash", err)
|
return h, coreerr.E("HashFromHex", "types: invalid hex for hash", err)
|
||||||
}
|
}
|
||||||
if len(b) != 32 {
|
if len(b) != 32 {
|
||||||
return h, coreerr.E("HashFromHex", fmt.Sprintf("types: hash hex must be 64 characters, got %d", len(s)), nil)
|
return h, coreerr.E("HashFromHex", core.Sprintf("types: hash hex must be 64 characters, got %d", len(s)), nil)
|
||||||
}
|
}
|
||||||
copy(h[:], b)
|
copy(h[:], b)
|
||||||
return h, nil
|
return h, nil
|
||||||
|
|
@ -70,7 +69,7 @@ func PublicKeyFromHex(s string) (PublicKey, error) {
|
||||||
return pk, coreerr.E("PublicKeyFromHex", "types: invalid hex for public key", err)
|
return pk, coreerr.E("PublicKeyFromHex", "types: invalid hex for public key", err)
|
||||||
}
|
}
|
||||||
if len(b) != 32 {
|
if len(b) != 32 {
|
||||||
return pk, coreerr.E("PublicKeyFromHex", fmt.Sprintf("types: public key hex must be 64 characters, got %d", len(s)), nil)
|
return pk, coreerr.E("PublicKeyFromHex", core.Sprintf("types: public key hex must be 64 characters, got %d", len(s)), nil)
|
||||||
}
|
}
|
||||||
copy(pk[:], b)
|
copy(pk[:], b)
|
||||||
return pk, nil
|
return pk, nil
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"golang.org/x/crypto/argon2"
|
"golang.org/x/crypto/argon2"
|
||||||
|
|
@ -113,10 +113,7 @@ func (a *Account) Address() types.Address {
|
||||||
// Save encrypts the account with Argon2id + AES-256-GCM and persists it to
|
// Save encrypts the account with Argon2id + AES-256-GCM and persists it to
|
||||||
// the given store. The stored blob layout is: salt (16) | nonce (12) | ciphertext.
|
// the given store. The stored blob layout is: salt (16) | nonce (12) | ciphertext.
|
||||||
func (a *Account) Save(s *store.Store, password string) error {
|
func (a *Account) Save(s *store.Store, password string) error {
|
||||||
plaintext, err := json.Marshal(a)
|
plaintext := []byte(core.JSONMarshalString(a))
|
||||||
if err != nil {
|
|
||||||
return coreerr.E("Account.Save", "wallet: marshal account", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
salt := make([]byte, saltLen)
|
salt := make([]byte, saltLen)
|
||||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||||
|
|
@ -187,8 +184,8 @@ func LoadAccount(s *store.Store, password string) (*Account, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var acc Account
|
var acc Account
|
||||||
if err := json.Unmarshal(plaintext, &acc); err != nil {
|
if r := core.JSONUnmarshalString(string(plaintext), &acc); !r.OK {
|
||||||
return nil, coreerr.E("LoadAccount", "wallet: unmarshal account", err)
|
return nil, coreerr.E("LoadAccount", "wallet: unmarshal account", r.Value.(error))
|
||||||
}
|
}
|
||||||
return &acc, nil
|
return &acc, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ package wallet
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmp"
|
"cmp"
|
||||||
"fmt"
|
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/config"
|
"dappco.re/go/core/blockchain/config"
|
||||||
|
|
@ -83,7 +83,7 @@ func (b *V1Builder) Build(req *BuildRequest) (*types.Transaction, error) {
|
||||||
destTotal += dst.Amount
|
destTotal += dst.Amount
|
||||||
}
|
}
|
||||||
if sourceTotal < destTotal+req.Fee {
|
if sourceTotal < destTotal+req.Fee {
|
||||||
return nil, coreerr.E("V1Builder.Build", fmt.Sprintf("wallet: insufficient funds: have %d, need %d", sourceTotal, destTotal+req.Fee), nil)
|
return nil, coreerr.E("V1Builder.Build", core.Sprintf("wallet: insufficient funds: have %d, need %d", sourceTotal, destTotal+req.Fee), nil)
|
||||||
}
|
}
|
||||||
change := sourceTotal - destTotal - req.Fee
|
change := sourceTotal - destTotal - req.Fee
|
||||||
|
|
||||||
|
|
@ -101,7 +101,7 @@ func (b *V1Builder) Build(req *BuildRequest) (*types.Transaction, error) {
|
||||||
for i, src := range req.Sources {
|
for i, src := range req.Sources {
|
||||||
input, meta, buildErr := b.buildInput(&src)
|
input, meta, buildErr := b.buildInput(&src)
|
||||||
if buildErr != nil {
|
if buildErr != nil {
|
||||||
return nil, coreerr.E("V1Builder.Build", fmt.Sprintf("wallet: input %d", i), buildErr)
|
return nil, coreerr.E("V1Builder.Build", core.Sprintf("wallet: input %d", i), buildErr)
|
||||||
}
|
}
|
||||||
tx.Vin = append(tx.Vin, input)
|
tx.Vin = append(tx.Vin, input)
|
||||||
metas[i] = meta
|
metas[i] = meta
|
||||||
|
|
@ -112,7 +112,7 @@ func (b *V1Builder) Build(req *BuildRequest) (*types.Transaction, error) {
|
||||||
for _, dst := range req.Destinations {
|
for _, dst := range req.Destinations {
|
||||||
out, outErr := deriveOutput(txSec, dst.Address, outputIdx, dst.Amount)
|
out, outErr := deriveOutput(txSec, dst.Address, outputIdx, dst.Amount)
|
||||||
if outErr != nil {
|
if outErr != nil {
|
||||||
return nil, coreerr.E("V1Builder.Build", fmt.Sprintf("wallet: output %d", outputIdx), outErr)
|
return nil, coreerr.E("V1Builder.Build", core.Sprintf("wallet: output %d", outputIdx), outErr)
|
||||||
}
|
}
|
||||||
tx.Vout = append(tx.Vout, out)
|
tx.Vout = append(tx.Vout, out)
|
||||||
outputIdx++
|
outputIdx++
|
||||||
|
|
@ -136,7 +136,7 @@ func (b *V1Builder) Build(req *BuildRequest) (*types.Transaction, error) {
|
||||||
for i, meta := range metas {
|
for i, meta := range metas {
|
||||||
sigs, signErr := b.signer.SignInput(prefixHash, meta.ephemeral, meta.ring, meta.realIndex)
|
sigs, signErr := b.signer.SignInput(prefixHash, meta.ephemeral, meta.ring, meta.realIndex)
|
||||||
if signErr != nil {
|
if signErr != nil {
|
||||||
return nil, coreerr.E("V1Builder.Build", fmt.Sprintf("wallet: sign input %d", i), signErr)
|
return nil, coreerr.E("V1Builder.Build", core.Sprintf("wallet: sign input %d", i), signErr)
|
||||||
}
|
}
|
||||||
tx.Signatures = append(tx.Signatures, sigs)
|
tx.Signatures = append(tx.Signatures, sigs)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,9 @@
|
||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"dappco.re/go/core"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/types"
|
"dappco.re/go/core/blockchain/types"
|
||||||
"dappco.re/go/core/blockchain/wire"
|
"dappco.re/go/core/blockchain/wire"
|
||||||
|
|
@ -59,7 +58,7 @@ func ParseTxExtra(raw []byte) (*TxExtra, error) {
|
||||||
switch tag {
|
switch tag {
|
||||||
case extraTagPublicKey:
|
case extraTagPublicKey:
|
||||||
if pos+32 > len(raw) {
|
if pos+32 > len(raw) {
|
||||||
return extra, coreerr.E("ParseTxExtra", fmt.Sprintf("wallet: extra: truncated public key at offset %d", pos), nil)
|
return extra, coreerr.E("ParseTxExtra", core.Sprintf("wallet: extra: truncated public key at offset %d", pos), nil)
|
||||||
}
|
}
|
||||||
copy(extra.TxPublicKey[:], raw[pos:pos+32])
|
copy(extra.TxPublicKey[:], raw[pos:pos+32])
|
||||||
pos += 32
|
pos += 32
|
||||||
|
|
@ -112,11 +111,11 @@ func skipExtraElement(data []byte, tag uint8) (int, error) {
|
||||||
// String types: varint(length) + length bytes.
|
// String types: varint(length) + length bytes.
|
||||||
case 7, 9, 11, 19:
|
case 7, 9, 11, 19:
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return 0, coreerr.E("skipExtraElement", fmt.Sprintf("wallet: extra: no data for string tag %d", tag), nil)
|
return 0, coreerr.E("skipExtraElement", core.Sprintf("wallet: extra: no data for string tag %d", tag), nil)
|
||||||
}
|
}
|
||||||
length, n, err := wire.DecodeVarint(data)
|
length, n, err := wire.DecodeVarint(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, coreerr.E("skipExtraElement", fmt.Sprintf("wallet: extra: invalid string length for tag %d", tag), err)
|
return 0, coreerr.E("skipExtraElement", core.Sprintf("wallet: extra: invalid string length for tag %d", tag), err)
|
||||||
}
|
}
|
||||||
return n + int(length), nil
|
return n + int(length), nil
|
||||||
|
|
||||||
|
|
@ -124,7 +123,7 @@ func skipExtraElement(data []byte, tag uint8) (int, error) {
|
||||||
case 14, 15, 16, 26, 27:
|
case 14, 15, 16, 26, 27:
|
||||||
_, n, err := wire.DecodeVarint(data)
|
_, n, err := wire.DecodeVarint(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, coreerr.E("skipExtraElement", fmt.Sprintf("wallet: extra: invalid varint for tag %d", tag), err)
|
return 0, coreerr.E("skipExtraElement", core.Sprintf("wallet: extra: invalid varint for tag %d", tag), err)
|
||||||
}
|
}
|
||||||
return n, nil
|
return n, nil
|
||||||
|
|
||||||
|
|
@ -141,6 +140,6 @@ func skipExtraElement(data []byte, tag uint8) (int, error) {
|
||||||
return 64, nil // signature
|
return 64, nil // signature
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0, coreerr.E("skipExtraElement", fmt.Sprintf("wallet: extra: unknown tag %d", tag), nil)
|
return 0, coreerr.E("skipExtraElement", core.Sprintf("wallet: extra: unknown tag %d", tag), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@ package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,7 +13,7 @@ const numWords = 1626
|
||||||
// MnemonicEncode converts a 32-byte secret key to a 25-word mnemonic phrase.
|
// MnemonicEncode converts a 32-byte secret key to a 25-word mnemonic phrase.
|
||||||
func MnemonicEncode(key []byte) (string, error) {
|
func MnemonicEncode(key []byte) (string, error) {
|
||||||
if len(key) != 32 {
|
if len(key) != 32 {
|
||||||
return "", coreerr.E("MnemonicEncode", fmt.Sprintf("wallet: mnemonic encode requires 32 bytes, got %d", len(key)), nil)
|
return "", coreerr.E("MnemonicEncode", core.Sprintf("wallet: mnemonic encode requires 32 bytes, got %d", len(key)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
words := make([]string, 0, 25)
|
words := make([]string, 0, 25)
|
||||||
|
|
@ -31,16 +30,16 @@ func MnemonicEncode(key []byte) (string, error) {
|
||||||
checkIdx := checksumIndex(words)
|
checkIdx := checksumIndex(words)
|
||||||
words = append(words, words[checkIdx])
|
words = append(words, words[checkIdx])
|
||||||
|
|
||||||
return strings.Join(words, " "), nil
|
return core.Join(" ", words...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MnemonicDecode converts a 25-word mnemonic phrase to a 32-byte secret key.
|
// MnemonicDecode converts a 25-word mnemonic phrase to a 32-byte secret key.
|
||||||
func MnemonicDecode(phrase string) ([32]byte, error) {
|
func MnemonicDecode(phrase string) ([32]byte, error) {
|
||||||
var key [32]byte
|
var key [32]byte
|
||||||
|
|
||||||
words := strings.Fields(phrase)
|
words := mnemonicWords(phrase)
|
||||||
if len(words) != 25 {
|
if len(words) != 25 {
|
||||||
return key, coreerr.E("MnemonicDecode", fmt.Sprintf("wallet: mnemonic requires 25 words, got %d", len(words)), nil)
|
return key, coreerr.E("MnemonicDecode", core.Sprintf("wallet: mnemonic requires 25 words, got %d", len(words)), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := checksumIndex(words[:24])
|
expected := checksumIndex(words[:24])
|
||||||
|
|
@ -62,7 +61,7 @@ func MnemonicDecode(phrase string) ([32]byte, error) {
|
||||||
if !ok3 {
|
if !ok3 {
|
||||||
word = words[i*3+2]
|
word = words[i*3+2]
|
||||||
}
|
}
|
||||||
return key, coreerr.E("MnemonicDecode", fmt.Sprintf("wallet: unknown mnemonic word %q", word), nil)
|
return key, coreerr.E("MnemonicDecode", core.Sprintf("wallet: unknown mnemonic word %q", word), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
val := uint32(w1) +
|
val := uint32(w1) +
|
||||||
|
|
@ -74,6 +73,21 @@ func MnemonicDecode(phrase string) ([32]byte, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mnemonicWords(phrase string) []string {
|
||||||
|
normalised := core.Trim(phrase)
|
||||||
|
for _, ws := range []string{"\n", "\r", "\t"} {
|
||||||
|
normalised = core.Replace(normalised, ws, " ")
|
||||||
|
}
|
||||||
|
parts := core.Split(normalised, " ")
|
||||||
|
words := make([]string, 0, len(parts))
|
||||||
|
for _, part := range parts {
|
||||||
|
if part != "" {
|
||||||
|
words = append(words, part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return words
|
||||||
|
}
|
||||||
|
|
||||||
func checksumIndex(words []string) int {
|
func checksumIndex(words []string) int {
|
||||||
var prefixes string
|
var prefixes string
|
||||||
for _, w := range words {
|
for _, w := range words {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@
|
||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/rpc"
|
"dappco.re/go/core/blockchain/rpc"
|
||||||
|
|
@ -70,7 +69,7 @@ func (s *RPCRingSelector) SelectRing(amount uint64, realGlobalIndex uint64, ring
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(members) < ringSize {
|
if len(members) < ringSize {
|
||||||
return nil, coreerr.E("RPCRingSelector.SelectRing", fmt.Sprintf("wallet: insufficient decoys: got %d, need %d", len(members), ringSize), nil)
|
return nil, coreerr.E("RPCRingSelector.SelectRing", core.Sprintf("wallet: insufficient decoys: got %d, need %d", len(members), ringSize), nil)
|
||||||
}
|
}
|
||||||
return members, nil
|
return members, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@
|
||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"dappco.re/go/core"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
store "dappco.re/go/core/store"
|
store "dappco.re/go/core/store"
|
||||||
|
|
@ -66,22 +64,18 @@ func (t *Transfer) IsSpendable(chainHeight uint64, _ bool) bool {
|
||||||
// putTransfer serialises a transfer as JSON and stores it in the given store,
|
// putTransfer serialises a transfer as JSON and stores it in the given store,
|
||||||
// keyed by the transfer's key image hex string.
|
// keyed by the transfer's key image hex string.
|
||||||
func putTransfer(s *store.Store, tr *Transfer) error {
|
func putTransfer(s *store.Store, tr *Transfer) error {
|
||||||
val, err := json.Marshal(tr)
|
return s.Set(groupTransfers, tr.KeyImage.String(), core.JSONMarshalString(tr))
|
||||||
if err != nil {
|
|
||||||
return coreerr.E("putTransfer", "wallet: marshal transfer", err)
|
|
||||||
}
|
|
||||||
return s.Set(groupTransfers, tr.KeyImage.String(), string(val))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTransfer retrieves and deserialises a transfer by its key image.
|
// getTransfer retrieves and deserialises a transfer by its key image.
|
||||||
func getTransfer(s *store.Store, ki types.KeyImage) (*Transfer, error) {
|
func getTransfer(s *store.Store, ki types.KeyImage) (*Transfer, error) {
|
||||||
val, err := s.Get(groupTransfers, ki.String())
|
val, err := s.Get(groupTransfers, ki.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, coreerr.E("getTransfer", fmt.Sprintf("wallet: get transfer %s", ki), err)
|
return nil, coreerr.E("getTransfer", core.Sprintf("wallet: get transfer %s", ki), err)
|
||||||
}
|
}
|
||||||
var tr Transfer
|
var tr Transfer
|
||||||
if err := json.Unmarshal([]byte(val), &tr); err != nil {
|
if r := core.JSONUnmarshalString(val, &tr); !r.OK {
|
||||||
return nil, coreerr.E("getTransfer", "wallet: unmarshal transfer", err)
|
return nil, coreerr.E("getTransfer", "wallet: unmarshal transfer", r.Value.(error))
|
||||||
}
|
}
|
||||||
return &tr, nil
|
return &tr, nil
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +101,7 @@ func listTransfers(s *store.Store) ([]Transfer, error) {
|
||||||
transfers := make([]Transfer, 0, len(pairs))
|
transfers := make([]Transfer, 0, len(pairs))
|
||||||
for _, val := range pairs {
|
for _, val := range pairs {
|
||||||
var tr Transfer
|
var tr Transfer
|
||||||
if err := json.Unmarshal([]byte(val), &tr); err != nil {
|
if r := core.JSONUnmarshalString(val, &tr); !r.OK {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
transfers = append(transfers, tr)
|
transfers = append(transfers, tr)
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"fmt"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/chain"
|
"dappco.re/go/core/blockchain/chain"
|
||||||
|
|
@ -77,7 +77,7 @@ func (w *Wallet) Sync() error {
|
||||||
for h := lastScanned; h < chainHeight; h++ {
|
for h := lastScanned; h < chainHeight; h++ {
|
||||||
blk, _, err := w.chain.GetBlockByHeight(h)
|
blk, _, err := w.chain.GetBlockByHeight(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("Wallet.Sync", fmt.Sprintf("wallet: get block %d", h), err)
|
return coreerr.E("Wallet.Sync", core.Sprintf("wallet: get block %d", h), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan miner tx.
|
// Scan miner tx.
|
||||||
|
|
@ -209,7 +209,7 @@ func (w *Wallet) Send(destinations []Destination, fee uint64) (*types.Transactio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if selectedSum < needed {
|
if selectedSum < needed {
|
||||||
return nil, coreerr.E("Wallet.Send", fmt.Sprintf("wallet: insufficient balance: have %d, need %d", selectedSum, needed), nil)
|
return nil, coreerr.E("Wallet.Send", core.Sprintf("wallet: insufficient balance: have %d, need %d", selectedSum, needed), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &BuildRequest{
|
req := &BuildRequest{
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ package wire
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"dappco.re/go/core"
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -82,7 +82,7 @@ func (d *Decoder) ReadBytes(n int) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if n < 0 || n > MaxBlobSize {
|
if n < 0 || n > MaxBlobSize {
|
||||||
d.err = coreerr.E("Decoder.ReadBytes", fmt.Sprintf("wire: blob size %d exceeds maximum %d", n, MaxBlobSize), nil)
|
d.err = coreerr.E("Decoder.ReadBytes", core.Sprintf("wire: blob size %d exceeds maximum %d", n, MaxBlobSize), nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
buf := make([]byte, n)
|
buf := make([]byte, n)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@
|
||||||
package wire
|
package wire
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"dappco.re/go/core"
|
||||||
|
|
||||||
coreerr "dappco.re/go/core/log"
|
coreerr "dappco.re/go/core/log"
|
||||||
|
|
||||||
"dappco.re/go/core/blockchain/types"
|
"dappco.re/go/core/blockchain/types"
|
||||||
|
|
@ -223,7 +222,7 @@ func decodeInputs(dec *Decoder) []types.TxInput {
|
||||||
in.EtcDetails = decodeRawVariantVector(dec)
|
in.EtcDetails = decodeRawVariantVector(dec)
|
||||||
vin = append(vin, in)
|
vin = append(vin, in)
|
||||||
default:
|
default:
|
||||||
dec.err = coreerr.E("decodeInputs", fmt.Sprintf("wire: unsupported input tag 0x%02x", tag), nil)
|
dec.err = coreerr.E("decodeInputs", core.Sprintf("wire: unsupported input tag 0x%02x", tag), nil)
|
||||||
return vin
|
return vin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -261,7 +260,7 @@ func decodeKeyOffsets(dec *Decoder) []types.TxOutRef {
|
||||||
dec.ReadBlob32((*[32]byte)(&refs[i].TxID))
|
dec.ReadBlob32((*[32]byte)(&refs[i].TxID))
|
||||||
refs[i].N = dec.ReadVarint()
|
refs[i].N = dec.ReadVarint()
|
||||||
default:
|
default:
|
||||||
dec.err = coreerr.E("decodeKeyOffsets", fmt.Sprintf("wire: unsupported ref tag 0x%02x", refs[i].Tag), nil)
|
dec.err = coreerr.E("decodeKeyOffsets", core.Sprintf("wire: unsupported ref tag 0x%02x", refs[i].Tag), nil)
|
||||||
return refs
|
return refs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -340,7 +339,7 @@ func decodeOutputsV1(dec *Decoder) []types.TxOutput {
|
||||||
dec.ReadBlob32((*[32]byte)(&t.PKRefund))
|
dec.ReadBlob32((*[32]byte)(&t.PKRefund))
|
||||||
out.Target = t
|
out.Target = t
|
||||||
default:
|
default:
|
||||||
dec.err = coreerr.E("decodeOutputsV1", fmt.Sprintf("wire: unsupported target tag 0x%02x", tag), nil)
|
dec.err = coreerr.E("decodeOutputsV1", core.Sprintf("wire: unsupported target tag 0x%02x", tag), nil)
|
||||||
return vout
|
return vout
|
||||||
}
|
}
|
||||||
vout = append(vout, out)
|
vout = append(vout, out)
|
||||||
|
|
@ -427,7 +426,7 @@ func decodeOutputsV2(dec *Decoder) []types.TxOutput {
|
||||||
dec.ReadBlob32((*[32]byte)(&t.PKRefund))
|
dec.ReadBlob32((*[32]byte)(&t.PKRefund))
|
||||||
out.Target = t
|
out.Target = t
|
||||||
default:
|
default:
|
||||||
dec.err = coreerr.E("decodeOutputsV2", fmt.Sprintf("wire: unsupported target tag 0x%02x", targetTag), nil)
|
dec.err = coreerr.E("decodeOutputsV2", core.Sprintf("wire: unsupported target tag 0x%02x", targetTag), nil)
|
||||||
return vout
|
return vout
|
||||||
}
|
}
|
||||||
vout = append(vout, out)
|
vout = append(vout, out)
|
||||||
|
|
@ -441,7 +440,7 @@ func decodeOutputsV2(dec *Decoder) []types.TxOutput {
|
||||||
out.MixAttr = dec.ReadUint8()
|
out.MixAttr = dec.ReadUint8()
|
||||||
vout = append(vout, out)
|
vout = append(vout, out)
|
||||||
default:
|
default:
|
||||||
dec.err = coreerr.E("decodeOutputsV2", fmt.Sprintf("wire: unsupported output tag 0x%02x", tag), nil)
|
dec.err = coreerr.E("decodeOutputsV2", core.Sprintf("wire: unsupported output tag 0x%02x", tag), nil)
|
||||||
return vout
|
return vout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -627,7 +626,7 @@ func readVariantElementData(dec *Decoder, tag uint8) []byte {
|
||||||
return dec.ReadBytes(96)
|
return dec.ReadBytes(96)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dec.err = coreerr.E("readVariantElementData", fmt.Sprintf("wire: unsupported variant tag 0x%02x (%d)", tag, tag), nil)
|
dec.err = coreerr.E("readVariantElementData", core.Sprintf("wire: unsupported variant tag 0x%02x (%d)", tag, tag), nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,7 @@
|
||||||
// to the C++ reference implementation.
|
// to the C++ reference implementation.
|
||||||
package wire
|
package wire
|
||||||
|
|
||||||
import (
|
import "dappco.re/go/core"
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MaxVarintLen is the maximum number of bytes a CryptoNote varint can occupy.
|
// MaxVarintLen is the maximum number of bytes a CryptoNote varint can occupy.
|
||||||
// A uint64 requires at most 10 bytes of 7-bit encoding (64 bits / 7 = ~9.14,
|
// A uint64 requires at most 10 bytes of 7-bit encoding (64 bits / 7 = ~9.14,
|
||||||
|
|
@ -23,11 +21,11 @@ const MaxVarintLen = 10
|
||||||
|
|
||||||
// ErrVarintOverflow is returned when a varint exceeds the maximum allowed
|
// ErrVarintOverflow is returned when a varint exceeds the maximum allowed
|
||||||
// length of 10 bytes.
|
// length of 10 bytes.
|
||||||
var ErrVarintOverflow = errors.New("wire: varint overflow (exceeds 10 bytes)")
|
var ErrVarintOverflow = core.E("", "wire: varint overflow (exceeds 10 bytes)", nil)
|
||||||
|
|
||||||
// ErrVarintEmpty is returned when attempting to decode a varint from an
|
// ErrVarintEmpty is returned when attempting to decode a varint from an
|
||||||
// empty byte slice.
|
// empty byte slice.
|
||||||
var ErrVarintEmpty = errors.New("wire: cannot decode varint from empty data")
|
var ErrVarintEmpty = core.E("", "wire: cannot decode varint from empty data", nil)
|
||||||
|
|
||||||
// EncodeVarint encodes a uint64 value as a CryptoNote variable-length integer.
|
// EncodeVarint encodes a uint64 value as a CryptoNote variable-length integer.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue