| name | bch-development |
| description | Bitcoin Cash (BCH) API implementation rules. Critical pattern for embedding Bitcoin struct and overriding BCH-specific methods. Use when working on BCH-related code in internal/infrastructure/api/btc/bch/. |
BCH (Bitcoin Cash) Development Rules
🚨 CRITICAL: Override Pattern for BCH-Specific Logic
This is a non-negotiable architectural rule. BCH implementation uses struct embedding with method override pattern.
Architecture Overview
type BitcoinCash struct {
apibtcimpl.Bitcoin
}
Key Principle: BitcoinCash embeds Bitcoin, inheriting all BTC methods by default.
Rules
✅ DO: Override on BCH Side
When BCH requires different logic from BTC:
- Create a new file in
internal/infrastructure/api/btc/bch/
- Implement the method with the same name on
BitcoinCash
- This "overrides" the embedded
Bitcoin method
❌ DON'T: Modify BTC Side for BCH
- NEVER modify
internal/infrastructure/api/btc/btc/ for BCH-specific requirements
- NEVER add BCH conditionals in BTC code
- NEVER add BCH-specific types or logic to the BTC package
Why This Pattern?
| Reason | Explanation |
|---|
| Separation of Concerns | BTC code remains pure and focused |
| Maintainability | BCH changes don't affect BTC |
| Clarity | BCH differences are explicit in BCH directory |
| Safety | BTC modifications can't accidentally break BCH |
Implementation Examples
Example 1: GetAddressInfo Override
BCH has a different response structure for getaddressinfo RPC:
type GetAddressInfoResult struct {
Address string `json:"address"`
ScriptPubKey string `json:"scriptPubKey"`
Label string `json:"label,omitempty"`
Labels []struct {
Name string `json:"name"`
Purpose string `json:"purpose"`
} `json:"labels"`
}
func (b *BitcoinCash) GetAddressInfo(addr string) (*dtobtc.AddressInfo, error) {
}
Example 2: GetAccount Override
BCH requires different logic for getting account info:
func (b *BitcoinCash) GetAccount(addr string) (string, error) {
res, err := b.GetAddressInfo(addr)
if err != nil {
return "", fmt.Errorf("fail to call btc.GetAddressInfo() in bch: %w", err)
}
if len(res.Labels) == 0 {
return "", nil
}
return res.Labels[0], nil
}
Example 3: Chain Parameters Override
BCH has different network magic numbers:
const (
MainnetMagic wire.BitcoinNet = 0xe8f3e1e3
TestnetMagic wire.BitcoinNet = 0xf4f3e5f4
Regtestmagic wire.BitcoinNet = 0xfabfb5da
)
func (b *BitcoinCash) initChainParams() {
}
BCH vs BTC: Feature Differences
| Feature | BTC | BCH |
|---|
| SegWit | ✅ Supported | ❌ Not supported |
| Taproot | ✅ Supported | ❌ Not supported |
| Address Format | Legacy, SegWit, Taproot | Legacy, CashAddr |
| Network Magic | BTC values | BCH-specific values |
Directory Structure
internal/infrastructure/api/btc/
├── btc/ # BTC implementation (DO NOT modify for BCH)
│ ├── bitcoin.go # Bitcoin struct and methods
│ ├── account.go
│ ├── address.go
│ └── ...
├── bch/ # BCH overrides (ADD new files here)
│ ├── bitcoin_cash.go # BitcoinCash struct (embeds Bitcoin)
│ ├── account.go # Override: GetAccount
│ ├── address.go # Override: GetAddressInfo
│ └── ...
└── connection.go # Shared connection logic
Checklist for BCH Changes
When implementing BCH-specific logic:
Common Mistakes
❌ WRONG: Adding BCH Logic to BTC
func (b *Bitcoin) GetAccount(addr string) (string, error) {
if b.coinTypeCode == domainCoin.BCH {
}
}
✅ CORRECT: Override in BCH Package
func (b *BitcoinCash) GetAccount(addr string) (string, error) {
}
Technical Note: How Go Embedding Works
When BitcoinCash embeds Bitcoin:
- All
Bitcoin methods are "promoted" to BitcoinCash
- If
BitcoinCash defines a method with the same name, it takes precedence
- The embedded
Bitcoin methods can still be called via b.Bitcoin.MethodName()
info, _ := bch.GetAddressInfo(addr)
info, _ := bch.Bitcoin.GetAddressInfo(addr)
Related Files
| File | Purpose |
|---|
internal/infrastructure/api/btc/bch/bitcoin_cash.go | BitcoinCash struct definition |
internal/infrastructure/api/btc/btc/bitcoin.go | Bitcoin struct (embedded by BCH) |
internal/application/ports/btc/interface.go | Bitcoiner interface |
Related Documentation