mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-24 04:13:16 +00:00
Compare commits
1 Commits
v0.6.11-de
...
v0.6.1-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f3fb0bf9f |
@@ -40,8 +40,10 @@ recommended that `GOPATH` is set to a directory in your home directory such as
|
||||
```bash
|
||||
$ git clone https://github.com/kaspanet/kaspad $GOPATH/src/github.com/kaspanet/kaspad
|
||||
$ cd $GOPATH/src/github.com/kaspanet/kaspad
|
||||
$ ./test.sh
|
||||
$ go install . ./cmd/...
|
||||
```
|
||||
`./test.sh` tests can be skipped, but some things might not run correctly on your system if tests fail.
|
||||
|
||||
- Kaspad (and utilities) should now be installed in `$GOPATH/bin`. If you did
|
||||
not already add the bin directory to your system path during Go installation,
|
||||
|
||||
@@ -9,23 +9,21 @@ import (
|
||||
crand "crypto/rand" // for seeding
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/pkg/errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
@@ -94,7 +92,7 @@ type PeersStateForSerialization struct {
|
||||
}
|
||||
|
||||
type localAddress struct {
|
||||
netAddress *appmessage.NetAddress
|
||||
netAddress *domainmessage.NetAddress
|
||||
score AddressPriority
|
||||
}
|
||||
|
||||
@@ -194,7 +192,7 @@ const (
|
||||
var ErrAddressNotFound = errors.New("address not found")
|
||||
|
||||
// New returns a new Kaspa address manager.
|
||||
func New(cfg *config.Config, databaseContext *dbaccess.DatabaseContext) (*AddressManager, error) {
|
||||
func New(cfg *config.Config, databaseContext *dbaccess.DatabaseContext) *AddressManager {
|
||||
addressManager := AddressManager{
|
||||
cfg: cfg,
|
||||
databaseContext: databaseContext,
|
||||
@@ -204,17 +202,13 @@ func New(cfg *config.Config, databaseContext *dbaccess.DatabaseContext) (*Addres
|
||||
localAddresses: make(map[AddressKey]*localAddress),
|
||||
localSubnetworkID: cfg.SubnetworkID,
|
||||
}
|
||||
err := addressManager.initListeners()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addressManager.reset()
|
||||
return &addressManager, nil
|
||||
return &addressManager
|
||||
}
|
||||
|
||||
// updateAddress is a helper function to either update an address already known
|
||||
// to the address manager, or to add the address if not already known.
|
||||
func (am *AddressManager) updateAddress(netAddress, sourceAddress *appmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
func (am *AddressManager) updateAddress(netAddress, sourceAddress *domainmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
// Filter out non-routable addresses. Note that non-routable
|
||||
// also includes invalid and local addresses.
|
||||
if !am.IsRoutable(netAddress) {
|
||||
@@ -224,6 +218,7 @@ func (am *AddressManager) updateAddress(netAddress, sourceAddress *appmessage.Ne
|
||||
addressKey := NetAddressKey(netAddress)
|
||||
knownAddress := am.knownAddress(netAddress)
|
||||
if knownAddress != nil {
|
||||
// TODO: only update addresses periodically.
|
||||
// Update the last seen time and services.
|
||||
// note that to prevent causing excess garbage on getaddr
|
||||
// messages the netaddresses in addrmaanger are *immutable*,
|
||||
@@ -376,7 +371,7 @@ func (am *AddressManager) pickTried(subnetworkID *subnetworkid.SubnetworkID, buc
|
||||
return oldest, oldestIndex
|
||||
}
|
||||
|
||||
func (am *AddressManager) newAddressBucketIndex(netAddress, srcAddress *appmessage.NetAddress) int {
|
||||
func (am *AddressManager) newAddressBucketIndex(netAddress, srcAddress *domainmessage.NetAddress) int {
|
||||
// doublesha256(key + sourcegroup + int64(doublesha256(key + group + sourcegroup))%bucket_per_source_group) % num_new_buckets
|
||||
|
||||
data1 := []byte{}
|
||||
@@ -397,7 +392,7 @@ func (am *AddressManager) newAddressBucketIndex(netAddress, srcAddress *appmessa
|
||||
return int(binary.LittleEndian.Uint64(hash2) % NewBucketCount)
|
||||
}
|
||||
|
||||
func (am *AddressManager) triedAddressBucketIndex(netAddress *appmessage.NetAddress) int {
|
||||
func (am *AddressManager) triedAddressBucketIndex(netAddress *domainmessage.NetAddress) int {
|
||||
// doublesha256(key + group + truncate_to_64bits(doublesha256(key)) % buckets_per_group) % num_buckets
|
||||
data1 := []byte{}
|
||||
data1 = append(data1, am.key[:]...)
|
||||
@@ -710,8 +705,8 @@ func (am *AddressManager) deserializePeersState(serializedPeerState []byte) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeserializeNetAddress converts a given address string to a *appmessage.NetAddress
|
||||
func (am *AddressManager) DeserializeNetAddress(addressKey AddressKey) (*appmessage.NetAddress, error) {
|
||||
// DeserializeNetAddress converts a given address string to a *domainmessage.NetAddress
|
||||
func (am *AddressManager) DeserializeNetAddress(addressKey AddressKey) (*domainmessage.NetAddress, error) {
|
||||
host, portString, err := net.SplitHostPort(string(addressKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -721,7 +716,7 @@ func (am *AddressManager) DeserializeNetAddress(addressKey AddressKey) (*appmess
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return am.HostToNetAddress(host, uint16(port), appmessage.SFNodeNetwork)
|
||||
return am.HostToNetAddress(host, uint16(port), domainmessage.SFNodeNetwork)
|
||||
}
|
||||
|
||||
// Start begins the core address handler which manages a pool of known
|
||||
@@ -763,7 +758,7 @@ func (am *AddressManager) Stop() error {
|
||||
// AddAddresses adds new addresses to the address manager. It enforces a max
|
||||
// number of addresses and silently ignores duplicate addresses. It is
|
||||
// safe for concurrent access.
|
||||
func (am *AddressManager) AddAddresses(addresses []*appmessage.NetAddress, sourceAddress *appmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
func (am *AddressManager) AddAddresses(addresses []*domainmessage.NetAddress, sourceAddress *domainmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
@@ -775,13 +770,35 @@ func (am *AddressManager) AddAddresses(addresses []*appmessage.NetAddress, sourc
|
||||
// AddAddress adds a new address to the address manager. It enforces a max
|
||||
// number of addresses and silently ignores duplicate addresses. It is
|
||||
// safe for concurrent access.
|
||||
func (am *AddressManager) AddAddress(address, sourceAddress *appmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
func (am *AddressManager) AddAddress(address, sourceAddress *domainmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
am.updateAddress(address, sourceAddress, subnetworkID)
|
||||
}
|
||||
|
||||
// AddAddressByIP adds an address where we are given an ip:port and not a
|
||||
// domainmessage.NetAddress.
|
||||
func (am *AddressManager) AddAddressByIP(addressIP string, subnetworkID *subnetworkid.SubnetworkID) error {
|
||||
// Split IP and port
|
||||
ipString, portString, err := net.SplitHostPort(addressIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Put it in domainmessage.Netaddress
|
||||
ip := net.ParseIP(ipString)
|
||||
if ip == nil {
|
||||
return errors.Errorf("invalid ip %s", ipString)
|
||||
}
|
||||
port, err := strconv.ParseUint(portString, 10, 0)
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid port %s: %s", portString, err)
|
||||
}
|
||||
netAddress := domainmessage.NewNetAddressIPPort(ip, uint16(port), 0)
|
||||
am.AddAddress(netAddress, netAddress, subnetworkID) // XXX use correct src address
|
||||
return nil
|
||||
}
|
||||
|
||||
// numAddresses returns the number of addresses that belongs to a specific subnetwork id
|
||||
// which are known to the address manager.
|
||||
func (am *AddressManager) numAddresses(subnetworkID *subnetworkid.SubnetworkID) int {
|
||||
@@ -826,7 +843,7 @@ func (am *AddressManager) NeedMoreAddresses() bool {
|
||||
|
||||
// AddressCache returns the current address cache. It must be treated as
|
||||
// read-only (but since it is a copy now, this is not as dangerous).
|
||||
func (am *AddressManager) AddressCache(includeAllSubnetworks bool, subnetworkID *subnetworkid.SubnetworkID) []*appmessage.NetAddress {
|
||||
func (am *AddressManager) AddressCache(includeAllSubnetworks bool, subnetworkID *subnetworkid.SubnetworkID) []*domainmessage.NetAddress {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
@@ -834,7 +851,7 @@ func (am *AddressManager) AddressCache(includeAllSubnetworks bool, subnetworkID
|
||||
return nil
|
||||
}
|
||||
|
||||
allAddresses := []*appmessage.NetAddress{}
|
||||
allAddresses := []*domainmessage.NetAddress{}
|
||||
// Iteration order is undefined here, but we randomise it anyway.
|
||||
for _, v := range am.addressIndex {
|
||||
if includeAllSubnetworks || v.SubnetworkID().IsEqual(subnetworkID) {
|
||||
@@ -890,7 +907,7 @@ func (am *AddressManager) reset() {
|
||||
|
||||
// HostToNetAddress returns a netaddress given a host address. If
|
||||
// the host is not an IP address it will be resolved.
|
||||
func (am *AddressManager) HostToNetAddress(host string, port uint16, services appmessage.ServiceFlag) (*appmessage.NetAddress, error) {
|
||||
func (am *AddressManager) HostToNetAddress(host string, port uint16, services domainmessage.ServiceFlag) (*domainmessage.NetAddress, error) {
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
ips, err := am.lookupFunc(host)
|
||||
@@ -903,12 +920,12 @@ func (am *AddressManager) HostToNetAddress(host string, port uint16, services ap
|
||||
ip = ips[0]
|
||||
}
|
||||
|
||||
return appmessage.NewNetAddressIPPort(ip, port, services), nil
|
||||
return domainmessage.NewNetAddressIPPort(ip, port, services), nil
|
||||
}
|
||||
|
||||
// NetAddressKey returns a key in the form of ip:port for IPv4 addresses
|
||||
// or [ip]:port for IPv6 addresses for use as keys in maps.
|
||||
func NetAddressKey(netAddress *appmessage.NetAddress) AddressKey {
|
||||
func NetAddressKey(netAddress *domainmessage.NetAddress) AddressKey {
|
||||
port := strconv.FormatUint(uint64(netAddress.Port), 10)
|
||||
|
||||
return AddressKey(net.JoinHostPort(netAddress.IP.String(), port))
|
||||
@@ -1014,13 +1031,13 @@ func (tb *triedAddressBucketArray) name() string {
|
||||
return "tried"
|
||||
}
|
||||
|
||||
func (am *AddressManager) knownAddress(address *appmessage.NetAddress) *KnownAddress {
|
||||
func (am *AddressManager) knownAddress(address *domainmessage.NetAddress) *KnownAddress {
|
||||
return am.addressIndex[NetAddressKey(address)]
|
||||
}
|
||||
|
||||
// Attempt increases the given address' attempt counter and updates
|
||||
// the last attempt time.
|
||||
func (am *AddressManager) Attempt(address *appmessage.NetAddress) {
|
||||
func (am *AddressManager) Attempt(address *domainmessage.NetAddress) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
@@ -1038,7 +1055,7 @@ func (am *AddressManager) Attempt(address *appmessage.NetAddress) {
|
||||
// Connected Marks the given address as currently connected and working at the
|
||||
// current time. The address must already be known to AddressManager else it will
|
||||
// be ignored.
|
||||
func (am *AddressManager) Connected(address *appmessage.NetAddress) {
|
||||
func (am *AddressManager) Connected(address *domainmessage.NetAddress) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
@@ -1061,7 +1078,7 @@ func (am *AddressManager) Connected(address *appmessage.NetAddress) {
|
||||
// Good marks the given address as good. To be called after a successful
|
||||
// connection and version exchange. If the address is unknown to the address
|
||||
// manager it will be ignored.
|
||||
func (am *AddressManager) Good(address *appmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
func (am *AddressManager) Good(address *domainmessage.NetAddress, subnetworkID *subnetworkid.SubnetworkID) {
|
||||
am.mutex.Lock()
|
||||
defer am.mutex.Unlock()
|
||||
|
||||
@@ -1237,7 +1254,7 @@ func (am *AddressManager) incrementTriedAddressCount(subnetworkID *subnetworkid.
|
||||
|
||||
// AddLocalAddress adds netAddress to the list of known local addresses to advertise
|
||||
// with the given priority.
|
||||
func (am *AddressManager) AddLocalAddress(netAddress *appmessage.NetAddress, priority AddressPriority) error {
|
||||
func (am *AddressManager) AddLocalAddress(netAddress *domainmessage.NetAddress, priority AddressPriority) error {
|
||||
if !am.IsRoutable(netAddress) {
|
||||
return errors.Errorf("address %s is not routable", netAddress.IP)
|
||||
}
|
||||
@@ -1262,7 +1279,7 @@ func (am *AddressManager) AddLocalAddress(netAddress *appmessage.NetAddress, pri
|
||||
|
||||
// getReachabilityFrom returns the relative reachability of the provided local
|
||||
// address to the provided remote address.
|
||||
func (am *AddressManager) getReachabilityFrom(localAddress, remoteAddress *appmessage.NetAddress) int {
|
||||
func (am *AddressManager) getReachabilityFrom(localAddress, remoteAddress *domainmessage.NetAddress) int {
|
||||
const (
|
||||
Unreachable = 0
|
||||
Default = iota
|
||||
@@ -1329,13 +1346,13 @@ func (am *AddressManager) getReachabilityFrom(localAddress, remoteAddress *appme
|
||||
|
||||
// GetBestLocalAddress returns the most appropriate local address to use
|
||||
// for the given remote address.
|
||||
func (am *AddressManager) GetBestLocalAddress(remoteAddress *appmessage.NetAddress) *appmessage.NetAddress {
|
||||
func (am *AddressManager) GetBestLocalAddress(remoteAddress *domainmessage.NetAddress) *domainmessage.NetAddress {
|
||||
am.localAddressesLock.Lock()
|
||||
defer am.localAddressesLock.Unlock()
|
||||
|
||||
bestReach := 0
|
||||
var bestScore AddressPriority
|
||||
var bestAddress *appmessage.NetAddress
|
||||
var bestAddress *domainmessage.NetAddress
|
||||
for _, localAddress := range am.localAddresses {
|
||||
reach := am.getReachabilityFrom(localAddress.netAddress, remoteAddress)
|
||||
if reach > bestReach ||
|
||||
@@ -1359,24 +1376,24 @@ func (am *AddressManager) GetBestLocalAddress(remoteAddress *appmessage.NetAddre
|
||||
} else {
|
||||
ip = net.IPv4zero
|
||||
}
|
||||
services := appmessage.SFNodeNetwork | appmessage.SFNodeBloom
|
||||
bestAddress = appmessage.NewNetAddressIPPort(ip, 0, services)
|
||||
services := domainmessage.SFNodeNetwork | domainmessage.SFNodeBloom
|
||||
bestAddress = domainmessage.NewNetAddressIPPort(ip, 0, services)
|
||||
}
|
||||
|
||||
return bestAddress
|
||||
}
|
||||
|
||||
// Ban marks the given address as banned
|
||||
func (am *AddressManager) Ban(address *appmessage.NetAddress) error {
|
||||
func (am *AddressManager) Ban(address *domainmessage.NetAddress) error {
|
||||
return am.setBanned(address, true, mstime.Now())
|
||||
}
|
||||
|
||||
// Unban marks the given address as not banned
|
||||
func (am *AddressManager) Unban(address *appmessage.NetAddress) error {
|
||||
func (am *AddressManager) Unban(address *domainmessage.NetAddress) error {
|
||||
return am.setBanned(address, false, mstime.Time{})
|
||||
}
|
||||
|
||||
func (am *AddressManager) setBanned(address *appmessage.NetAddress, isBanned bool, bannedTime mstime.Time) error {
|
||||
func (am *AddressManager) setBanned(address *domainmessage.NetAddress, isBanned bool, bannedTime mstime.Time) error {
|
||||
am.localAddressesLock.Lock()
|
||||
defer am.localAddressesLock.Unlock()
|
||||
|
||||
@@ -1391,7 +1408,7 @@ func (am *AddressManager) setBanned(address *appmessage.NetAddress, isBanned boo
|
||||
}
|
||||
|
||||
// IsBanned returns whether the given address is banned
|
||||
func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) {
|
||||
func (am *AddressManager) IsBanned(address *domainmessage.NetAddress) (bool, error) {
|
||||
am.localAddressesLock.Lock()
|
||||
defer am.localAddressesLock.Unlock()
|
||||
|
||||
@@ -1402,188 +1419,3 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error)
|
||||
}
|
||||
return knownAddress.isBanned, nil
|
||||
}
|
||||
|
||||
// initListeners initializes the configured net listeners and adds any bound
|
||||
// addresses to the address manager
|
||||
func (am *AddressManager) initListeners() error {
|
||||
if len(am.cfg.ExternalIPs) != 0 {
|
||||
defaultPort, err := strconv.ParseUint(am.cfg.NetParams().DefaultPort, 10, 16)
|
||||
if err != nil {
|
||||
log.Errorf("Can not parse default port %s for active DAG: %s",
|
||||
am.cfg.NetParams().DefaultPort, err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sip := range am.cfg.ExternalIPs {
|
||||
eport := uint16(defaultPort)
|
||||
host, portstr, err := net.SplitHostPort(sip)
|
||||
if err != nil {
|
||||
// no port, use default.
|
||||
host = sip
|
||||
} else {
|
||||
port, err := strconv.ParseUint(portstr, 10, 16)
|
||||
if err != nil {
|
||||
log.Warnf("Can not parse port from %s for "+
|
||||
"externalip: %s", sip, err)
|
||||
continue
|
||||
}
|
||||
eport = uint16(port)
|
||||
}
|
||||
na, err := am.HostToNetAddress(host, eport, appmessage.DefaultServices)
|
||||
if err != nil {
|
||||
log.Warnf("Not adding %s as externalip: %s", sip, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = am.AddLocalAddress(na, ManualPrio)
|
||||
if err != nil {
|
||||
log.Warnf("Skipping specified external IP: %s", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Listen for TCP connections at the configured addresses
|
||||
netAddrs, err := parseListeners(am.cfg.Listeners)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add bound addresses to address manager to be advertised to peers.
|
||||
for _, addr := range netAddrs {
|
||||
listener, err := net.Listen(addr.Network(), addr.String())
|
||||
if err != nil {
|
||||
log.Warnf("Can't listen on %s: %s", addr, err)
|
||||
continue
|
||||
}
|
||||
addr := listener.Addr().String()
|
||||
err = listener.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = am.addLocalAddress(addr)
|
||||
if err != nil {
|
||||
log.Warnf("Skipping bound address %s: %s", addr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseListeners determines whether each listen address is IPv4 and IPv6 and
|
||||
// returns a slice of appropriate net.Addrs to listen on with TCP. It also
|
||||
// properly detects addresses which apply to "all interfaces" and adds the
|
||||
// address as both IPv4 and IPv6.
|
||||
func parseListeners(addrs []string) ([]net.Addr, error) {
|
||||
netAddrs := make([]net.Addr, 0, len(addrs)*2)
|
||||
for _, addr := range addrs {
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
// Shouldn't happen due to already being normalized.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Empty host or host of * on plan9 is both IPv4 and IPv6.
|
||||
if host == "" || (host == "*" && runtime.GOOS == "plan9") {
|
||||
netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr})
|
||||
netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr})
|
||||
continue
|
||||
}
|
||||
|
||||
// Strip IPv6 zone id if present since net.ParseIP does not
|
||||
// handle it.
|
||||
zoneIndex := strings.LastIndex(host, "%")
|
||||
if zoneIndex > 0 {
|
||||
host = host[:zoneIndex]
|
||||
}
|
||||
|
||||
// Parse the IP.
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
hostAddrs, err := net.LookupHost(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ip = net.ParseIP(hostAddrs[0])
|
||||
if ip == nil {
|
||||
return nil, errors.Errorf("Cannot resolve IP address for host '%s'", host)
|
||||
}
|
||||
}
|
||||
|
||||
// To4 returns nil when the IP is not an IPv4 address, so use
|
||||
// this determine the address type.
|
||||
if ip.To4() == nil {
|
||||
netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr})
|
||||
} else {
|
||||
netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr})
|
||||
}
|
||||
}
|
||||
return netAddrs, nil
|
||||
}
|
||||
|
||||
// addLocalAddress adds an address that this node is listening on to the
|
||||
// address manager so that it may be relayed to peers.
|
||||
func (am *AddressManager) addLocalAddress(addr string) error {
|
||||
host, portStr, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
port, err := strconv.ParseUint(portStr, 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() {
|
||||
// If bound to unspecified address, advertise all local interfaces
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
ifaceIP, _, err := net.ParseCIDR(addr.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// If bound to 0.0.0.0, do not add IPv6 interfaces and if bound to
|
||||
// ::, do not add IPv4 interfaces.
|
||||
if (ip.To4() == nil) != (ifaceIP.To4() == nil) {
|
||||
continue
|
||||
}
|
||||
|
||||
netAddr := appmessage.NewNetAddressIPPort(ifaceIP, uint16(port), appmessage.DefaultServices)
|
||||
am.AddLocalAddress(netAddr, BoundPrio)
|
||||
}
|
||||
} else {
|
||||
netAddr, err := am.HostToNetAddress(host, uint16(port), appmessage.DefaultServices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
am.AddLocalAddress(netAddr, BoundPrio)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// simpleAddr implements the net.Addr interface with two struct fields
|
||||
type simpleAddr struct {
|
||||
net, addr string
|
||||
}
|
||||
|
||||
// String returns the address.
|
||||
//
|
||||
// This is part of the net.Addr interface.
|
||||
func (a simpleAddr) String() string {
|
||||
return a.addr
|
||||
}
|
||||
|
||||
// Network returns the network.
|
||||
//
|
||||
// This is part of the net.Addr interface.
|
||||
func (a simpleAddr) Network() string {
|
||||
return a.net
|
||||
}
|
||||
|
||||
// Ensure simpleAddr implements the net.Addr interface.
|
||||
var _ net.Addr = simpleAddr{}
|
||||
@@ -6,25 +6,26 @@ package addressmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
)
|
||||
|
||||
// naTest is used to describe a test to be performed against the NetAddressKey
|
||||
// method.
|
||||
type naTest struct {
|
||||
in appmessage.NetAddress
|
||||
in domainmessage.NetAddress
|
||||
want AddressKey
|
||||
}
|
||||
|
||||
@@ -98,7 +99,7 @@ func addNaTests() {
|
||||
|
||||
func addNaTest(ip string, port uint16, want AddressKey) {
|
||||
nip := net.ParseIP(ip)
|
||||
na := *appmessage.NewNetAddressIPPort(nip, port, appmessage.SFNodeNetwork)
|
||||
na := *domainmessage.NewNetAddressIPPort(nip, port, domainmessage.SFNodeNetwork)
|
||||
test := naTest{na, want}
|
||||
naTests = append(naTests, test)
|
||||
}
|
||||
@@ -123,10 +124,7 @@ func newAddrManagerForTest(t *testing.T, testName string,
|
||||
t.Fatalf("error creating db: %s", err)
|
||||
}
|
||||
|
||||
addressManager, err = New(cfg, databaseContext)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating address manager: %s", err)
|
||||
}
|
||||
addressManager = New(cfg, databaseContext)
|
||||
|
||||
return addressManager, func() {
|
||||
err := databaseContext.Close()
|
||||
@@ -177,7 +175,7 @@ func TestAddAddressByIP(t *testing.T) {
|
||||
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil)
|
||||
defer teardown()
|
||||
for i, test := range tests {
|
||||
err := AddAddressByIP(amgr, test.addrIP, nil)
|
||||
err := amgr.AddAddressByIP(test.addrIP, nil)
|
||||
if test.err != nil && err == nil {
|
||||
t.Errorf("TestAddAddressByIP test %d failed expected an error and got none", i)
|
||||
continue
|
||||
@@ -196,37 +194,37 @@ func TestAddAddressByIP(t *testing.T) {
|
||||
|
||||
func TestAddLocalAddress(t *testing.T) {
|
||||
var tests = []struct {
|
||||
address appmessage.NetAddress
|
||||
address domainmessage.NetAddress
|
||||
priority AddressPriority
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
appmessage.NetAddress{IP: net.ParseIP("192.168.0.100")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("192.168.0.100")},
|
||||
InterfacePrio,
|
||||
false,
|
||||
},
|
||||
{
|
||||
appmessage.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
||||
InterfacePrio,
|
||||
true,
|
||||
},
|
||||
{
|
||||
appmessage.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
||||
BoundPrio,
|
||||
true,
|
||||
},
|
||||
{
|
||||
appmessage.NetAddress{IP: net.ParseIP("::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("::1")},
|
||||
InterfacePrio,
|
||||
false,
|
||||
},
|
||||
{
|
||||
appmessage.NetAddress{IP: net.ParseIP("fe80::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("fe80::1")},
|
||||
InterfacePrio,
|
||||
false,
|
||||
},
|
||||
{
|
||||
appmessage.NetAddress{IP: net.ParseIP("2620:100::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("2620:100::1")},
|
||||
InterfacePrio,
|
||||
true,
|
||||
},
|
||||
@@ -253,7 +251,7 @@ func TestAttempt(t *testing.T) {
|
||||
defer teardown()
|
||||
|
||||
// Add a new address and get it
|
||||
err := AddAddressByIP(amgr, someIP+":8333", nil)
|
||||
err := amgr.AddAddressByIP(someIP+":8333", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
@@ -276,7 +274,7 @@ func TestConnected(t *testing.T) {
|
||||
defer teardown()
|
||||
|
||||
// Add a new address and get it
|
||||
err := AddAddressByIP(amgr, someIP+":8333", nil)
|
||||
err := amgr.AddAddressByIP(someIP+":8333", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
@@ -300,7 +298,7 @@ func TestNeedMoreAddresses(t *testing.T) {
|
||||
if !b {
|
||||
t.Errorf("Expected that we need more addresses")
|
||||
}
|
||||
addrs := make([]*appmessage.NetAddress, addrsToAdd)
|
||||
addrs := make([]*domainmessage.NetAddress, addrsToAdd)
|
||||
|
||||
var err error
|
||||
for i := 0; i < addrsToAdd; i++ {
|
||||
@@ -311,7 +309,7 @@ func TestNeedMoreAddresses(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
srcAddr := domainmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
|
||||
amgr.AddAddresses(addrs, srcAddr, nil)
|
||||
numAddrs := amgr.TotalNumAddresses()
|
||||
@@ -329,7 +327,7 @@ func TestGood(t *testing.T) {
|
||||
amgr, teardown := newAddrManagerForTest(t, "TestGood", nil)
|
||||
defer teardown()
|
||||
addrsToAdd := 64 * 64
|
||||
addrs := make([]*appmessage.NetAddress, addrsToAdd)
|
||||
addrs := make([]*domainmessage.NetAddress, addrsToAdd)
|
||||
subnetworkCount := 32
|
||||
subnetworkIDs := make([]*subnetworkid.SubnetworkID, subnetworkCount)
|
||||
|
||||
@@ -346,7 +344,7 @@ func TestGood(t *testing.T) {
|
||||
subnetworkIDs[i] = &subnetworkid.SubnetworkID{0xff - byte(i)}
|
||||
}
|
||||
|
||||
srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
srcAddr := domainmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
|
||||
amgr.AddAddresses(addrs, srcAddr, nil)
|
||||
for i, addr := range addrs {
|
||||
@@ -376,9 +374,9 @@ func TestGood(t *testing.T) {
|
||||
func TestGoodChangeSubnetworkID(t *testing.T) {
|
||||
amgr, teardown := newAddrManagerForTest(t, "TestGoodChangeSubnetworkID", nil)
|
||||
defer teardown()
|
||||
addr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
addr := domainmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
addrKey := NetAddressKey(addr)
|
||||
srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
srcAddr := domainmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
||||
|
||||
oldSubnetwork := subnetworkid.SubnetworkIDNative
|
||||
amgr.AddAddress(addr, srcAddr, oldSubnetwork)
|
||||
@@ -454,7 +452,7 @@ func TestGetAddress(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add a new address and get it
|
||||
err := AddAddressByIP(amgr, someIP+":8332", localSubnetworkID)
|
||||
err := amgr.AddAddressByIP(someIP+":8332", localSubnetworkID)
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
@@ -481,7 +479,7 @@ func TestGetAddress(t *testing.T) {
|
||||
// Now we repeat the same process, but now the address has the expected subnetwork ID.
|
||||
|
||||
// Add a new address and get it
|
||||
err = AddAddressByIP(amgr, someIP+":8333", localSubnetworkID)
|
||||
err = amgr.AddAddressByIP(someIP+":8333", localSubnetworkID)
|
||||
if err != nil {
|
||||
t.Fatalf("Adding address failed: %v", err)
|
||||
}
|
||||
@@ -517,7 +515,7 @@ func TestGetAddress(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetBestLocalAddress(t *testing.T) {
|
||||
localAddrs := []appmessage.NetAddress{
|
||||
localAddrs := []domainmessage.NetAddress{
|
||||
{IP: net.ParseIP("192.168.0.100")},
|
||||
{IP: net.ParseIP("::1")},
|
||||
{IP: net.ParseIP("fe80::1")},
|
||||
@@ -525,36 +523,45 @@ func TestGetBestLocalAddress(t *testing.T) {
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
remoteAddr appmessage.NetAddress
|
||||
want0 appmessage.NetAddress
|
||||
want1 appmessage.NetAddress
|
||||
want2 appmessage.NetAddress
|
||||
want3 appmessage.NetAddress
|
||||
remoteAddr domainmessage.NetAddress
|
||||
want0 domainmessage.NetAddress
|
||||
want1 domainmessage.NetAddress
|
||||
want2 domainmessage.NetAddress
|
||||
want3 domainmessage.NetAddress
|
||||
}{
|
||||
{
|
||||
// Remote connection from public IPv4
|
||||
appmessage.NetAddress{IP: net.ParseIP("204.124.8.1")},
|
||||
appmessage.NetAddress{IP: net.IPv4zero},
|
||||
appmessage.NetAddress{IP: net.IPv4zero},
|
||||
appmessage.NetAddress{IP: net.ParseIP("204.124.8.100")},
|
||||
appmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("204.124.8.1")},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("204.124.8.100")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")},
|
||||
},
|
||||
{
|
||||
// Remote connection from private IPv4
|
||||
appmessage.NetAddress{IP: net.ParseIP("172.16.0.254")},
|
||||
appmessage.NetAddress{IP: net.IPv4zero},
|
||||
appmessage.NetAddress{IP: net.IPv4zero},
|
||||
appmessage.NetAddress{IP: net.IPv4zero},
|
||||
appmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("172.16.0.254")},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
},
|
||||
{
|
||||
// Remote connection from public IPv6
|
||||
appmessage.NetAddress{IP: net.ParseIP("2602:100:abcd::102")},
|
||||
appmessage.NetAddress{IP: net.IPv6zero},
|
||||
appmessage.NetAddress{IP: net.ParseIP("2001:470::1")},
|
||||
appmessage.NetAddress{IP: net.ParseIP("2001:470::1")},
|
||||
appmessage.NetAddress{IP: net.ParseIP("2001:470::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("2602:100:abcd::102")},
|
||||
domainmessage.NetAddress{IP: net.IPv6zero},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("2001:470::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("2001:470::1")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("2001:470::1")},
|
||||
},
|
||||
/* XXX
|
||||
{
|
||||
// Remote connection from Tor
|
||||
domainmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43::100")},
|
||||
domainmessage.NetAddress{IP: net.IPv4zero},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("204.124.8.100")},
|
||||
domainmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")},
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
amgr, teardown := newAddrManagerForTest(t, "TestGetBestLocalAddress", nil)
|
||||
@@ -585,7 +592,7 @@ func TestGetBestLocalAddress(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add a public IP to the list of local addresses.
|
||||
localAddr := appmessage.NetAddress{IP: net.ParseIP("204.124.8.100")}
|
||||
localAddr := domainmessage.NetAddress{IP: net.ParseIP("204.124.8.100")}
|
||||
amgr.AddLocalAddress(&localAddr, InterfacePrio)
|
||||
|
||||
// Test against want2
|
||||
@@ -599,7 +606,7 @@ func TestGetBestLocalAddress(t *testing.T) {
|
||||
}
|
||||
/*
|
||||
// Add a Tor generated IP address
|
||||
localAddr = appmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")}
|
||||
localAddr = domainmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")}
|
||||
amgr.AddLocalAddress(&localAddr, ManualPrio)
|
||||
// Test against want3
|
||||
for x, test := range tests {
|
||||
@@ -624,4 +631,5 @@ func TestNetAddressKey(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
package addressmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ func TstKnownAddressChance(ka *KnownAddress) float64 {
|
||||
return ka.chance()
|
||||
}
|
||||
|
||||
func TstNewKnownAddress(na *appmessage.NetAddress, attempts int,
|
||||
func TstNewKnownAddress(na *domainmessage.NetAddress, attempts int,
|
||||
lastattempt, lastsuccess mstime.Time, tried bool, refs int) *KnownAddress {
|
||||
return &KnownAddress{netAddress: na, attempts: attempts, lastAttempt: lastattempt,
|
||||
lastSuccess: lastsuccess, tried: tried, referenceCount: refs}
|
||||
@@ -5,18 +5,19 @@
|
||||
package addressmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
)
|
||||
|
||||
// KnownAddress tracks information about a known network address that is used
|
||||
// to determine how viable an address is.
|
||||
type KnownAddress struct {
|
||||
netAddress *appmessage.NetAddress
|
||||
sourceAddress *appmessage.NetAddress
|
||||
netAddress *domainmessage.NetAddress
|
||||
sourceAddress *domainmessage.NetAddress
|
||||
attempts int
|
||||
lastAttempt mstime.Time
|
||||
lastSuccess mstime.Time
|
||||
@@ -27,9 +28,9 @@ type KnownAddress struct {
|
||||
bannedTime mstime.Time
|
||||
}
|
||||
|
||||
// NetAddress returns the underlying appmessage.NetAddress associated with the
|
||||
// NetAddress returns the underlying domainmessage.NetAddress associated with the
|
||||
// known address.
|
||||
func (ka *KnownAddress) NetAddress() *appmessage.NetAddress {
|
||||
func (ka *KnownAddress) NetAddress() *domainmessage.NetAddress {
|
||||
return ka.netAddress
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
package addressmanager_test
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
)
|
||||
|
||||
func TestChance(t *testing.T) {
|
||||
@@ -22,27 +22,27 @@ func TestChance(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
//Test normal case
|
||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
addressmanager.TstNewKnownAddress(&domainmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
0, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0),
|
||||
1.0,
|
||||
}, {
|
||||
//Test case in which lastseen < 0
|
||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(20 * time.Second)},
|
||||
addressmanager.TstNewKnownAddress(&domainmessage.NetAddress{Timestamp: now.Add(20 * time.Second)},
|
||||
0, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0),
|
||||
1.0,
|
||||
}, {
|
||||
//Test case in which lastAttempt < 0
|
||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
addressmanager.TstNewKnownAddress(&domainmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
0, mstime.Now().Add(30*time.Minute), mstime.Now(), false, 0),
|
||||
1.0 * .01,
|
||||
}, {
|
||||
//Test case in which lastAttempt < ten minutes
|
||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
addressmanager.TstNewKnownAddress(&domainmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
0, mstime.Now().Add(-5*time.Minute), mstime.Now(), false, 0),
|
||||
1.0 * .01,
|
||||
}, {
|
||||
//Test case with several failed attempts.
|
||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
addressmanager.TstNewKnownAddress(&domainmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
||||
2, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0),
|
||||
1 / 1.5 / 1.5,
|
||||
},
|
||||
@@ -66,10 +66,10 @@ func TestIsBad(t *testing.T) {
|
||||
hoursOld := now.Add(-5 * time.Hour)
|
||||
zeroTime := mstime.Time{}
|
||||
|
||||
futureNa := &appmessage.NetAddress{Timestamp: future}
|
||||
minutesOldNa := &appmessage.NetAddress{Timestamp: minutesOld}
|
||||
monthOldNa := &appmessage.NetAddress{Timestamp: monthOld}
|
||||
currentNa := &appmessage.NetAddress{Timestamp: secondsOld}
|
||||
futureNa := &domainmessage.NetAddress{Timestamp: future}
|
||||
minutesOldNa := &domainmessage.NetAddress{Timestamp: minutesOld}
|
||||
monthOldNa := &domainmessage.NetAddress{Timestamp: monthOld}
|
||||
currentNa := &domainmessage.NetAddress{Timestamp: secondsOld}
|
||||
|
||||
//Test addresses that have been tried in the last minute.
|
||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(futureNa, 3, secondsOld, zeroTime, false, 0)) {
|
||||
@@ -5,7 +5,7 @@
|
||||
package addressmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
package addressmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"net"
|
||||
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -85,19 +86,19 @@ func ipNet(ip string, ones, bits int) net.IPNet {
|
||||
}
|
||||
|
||||
// IsIPv4 returns whether or not the given address is an IPv4 address.
|
||||
func IsIPv4(na *appmessage.NetAddress) bool {
|
||||
func IsIPv4(na *domainmessage.NetAddress) bool {
|
||||
return na.IP.To4() != nil
|
||||
}
|
||||
|
||||
// IsLocal returns whether or not the given address is a local address.
|
||||
func IsLocal(na *appmessage.NetAddress) bool {
|
||||
func IsLocal(na *domainmessage.NetAddress) bool {
|
||||
return na.IP.IsLoopback() || zero4Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC1918 returns whether or not the passed address is part of the IPv4
|
||||
// private network address space as defined by RFC1918 (10.0.0.0/8,
|
||||
// 172.16.0.0/12, or 192.168.0.0/16).
|
||||
func IsRFC1918(na *appmessage.NetAddress) bool {
|
||||
func IsRFC1918(na *domainmessage.NetAddress) bool {
|
||||
for _, rfc := range rfc1918Nets {
|
||||
if rfc.Contains(na.IP) {
|
||||
return true
|
||||
@@ -108,56 +109,56 @@ func IsRFC1918(na *appmessage.NetAddress) bool {
|
||||
|
||||
// IsRFC2544 returns whether or not the passed address is part of the IPv4
|
||||
// address space as defined by RFC2544 (198.18.0.0/15)
|
||||
func IsRFC2544(na *appmessage.NetAddress) bool {
|
||||
func IsRFC2544(na *domainmessage.NetAddress) bool {
|
||||
return rfc2544Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC3849 returns whether or not the passed address is part of the IPv6
|
||||
// documentation range as defined by RFC3849 (2001:DB8::/32).
|
||||
func IsRFC3849(na *appmessage.NetAddress) bool {
|
||||
func IsRFC3849(na *domainmessage.NetAddress) bool {
|
||||
return rfc3849Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC3927 returns whether or not the passed address is part of the IPv4
|
||||
// autoconfiguration range as defined by RFC3927 (169.254.0.0/16).
|
||||
func IsRFC3927(na *appmessage.NetAddress) bool {
|
||||
func IsRFC3927(na *domainmessage.NetAddress) bool {
|
||||
return rfc3927Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC3964 returns whether or not the passed address is part of the IPv6 to
|
||||
// IPv4 encapsulation range as defined by RFC3964 (2002::/16).
|
||||
func IsRFC3964(na *appmessage.NetAddress) bool {
|
||||
func IsRFC3964(na *domainmessage.NetAddress) bool {
|
||||
return rfc3964Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC4193 returns whether or not the passed address is part of the IPv6
|
||||
// unique local range as defined by RFC4193 (FC00::/7).
|
||||
func IsRFC4193(na *appmessage.NetAddress) bool {
|
||||
func IsRFC4193(na *domainmessage.NetAddress) bool {
|
||||
return rfc4193Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC4380 returns whether or not the passed address is part of the IPv6
|
||||
// teredo tunneling over UDP range as defined by RFC4380 (2001::/32).
|
||||
func IsRFC4380(na *appmessage.NetAddress) bool {
|
||||
func IsRFC4380(na *domainmessage.NetAddress) bool {
|
||||
return rfc4380Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC4843 returns whether or not the passed address is part of the IPv6
|
||||
// ORCHID range as defined by RFC4843 (2001:10::/28).
|
||||
func IsRFC4843(na *appmessage.NetAddress) bool {
|
||||
func IsRFC4843(na *domainmessage.NetAddress) bool {
|
||||
return rfc4843Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC4862 returns whether or not the passed address is part of the IPv6
|
||||
// stateless address autoconfiguration range as defined by RFC4862 (FE80::/64).
|
||||
func IsRFC4862(na *appmessage.NetAddress) bool {
|
||||
func IsRFC4862(na *domainmessage.NetAddress) bool {
|
||||
return rfc4862Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC5737 returns whether or not the passed address is part of the IPv4
|
||||
// documentation address space as defined by RFC5737 (192.0.2.0/24,
|
||||
// 198.51.100.0/24, 203.0.113.0/24)
|
||||
func IsRFC5737(na *appmessage.NetAddress) bool {
|
||||
func IsRFC5737(na *domainmessage.NetAddress) bool {
|
||||
for _, rfc := range rfc5737Net {
|
||||
if rfc.Contains(na.IP) {
|
||||
return true
|
||||
@@ -169,19 +170,19 @@ func IsRFC5737(na *appmessage.NetAddress) bool {
|
||||
|
||||
// IsRFC6052 returns whether or not the passed address is part of the IPv6
|
||||
// well-known prefix range as defined by RFC6052 (64:FF9B::/96).
|
||||
func IsRFC6052(na *appmessage.NetAddress) bool {
|
||||
func IsRFC6052(na *domainmessage.NetAddress) bool {
|
||||
return rfc6052Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC6145 returns whether or not the passed address is part of the IPv6 to
|
||||
// IPv4 translated address range as defined by RFC6145 (::FFFF:0:0:0/96).
|
||||
func IsRFC6145(na *appmessage.NetAddress) bool {
|
||||
func IsRFC6145(na *domainmessage.NetAddress) bool {
|
||||
return rfc6145Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
// IsRFC6598 returns whether or not the passed address is part of the IPv4
|
||||
// shared address space specified by RFC6598 (100.64.0.0/10)
|
||||
func IsRFC6598(na *appmessage.NetAddress) bool {
|
||||
func IsRFC6598(na *domainmessage.NetAddress) bool {
|
||||
return rfc6598Net.Contains(na.IP)
|
||||
}
|
||||
|
||||
@@ -189,7 +190,7 @@ func IsRFC6598(na *appmessage.NetAddress) bool {
|
||||
// considered invalid under the following circumstances:
|
||||
// IPv4: It is either a zero or all bits set address.
|
||||
// IPv6: It is either a zero or RFC3849 documentation address.
|
||||
func IsValid(na *appmessage.NetAddress) bool {
|
||||
func IsValid(na *domainmessage.NetAddress) bool {
|
||||
// IsUnspecified returns if address is 0, so only all bits set, and
|
||||
// RFC3849 need to be explicitly checked.
|
||||
return na.IP != nil && !(na.IP.IsUnspecified() ||
|
||||
@@ -199,7 +200,7 @@ func IsValid(na *appmessage.NetAddress) bool {
|
||||
// IsRoutable returns whether or not the passed address is routable over
|
||||
// the public internet. This is true as long as the address is valid and is not
|
||||
// in any reserved ranges.
|
||||
func (am *AddressManager) IsRoutable(na *appmessage.NetAddress) bool {
|
||||
func (am *AddressManager) IsRoutable(na *domainmessage.NetAddress) bool {
|
||||
if am.cfg.NetParams().AcceptUnroutable {
|
||||
return !IsLocal(na)
|
||||
}
|
||||
@@ -214,7 +215,7 @@ func (am *AddressManager) IsRoutable(na *appmessage.NetAddress) bool {
|
||||
// of. This is the /16 for IPv4, the /32 (/36 for he.net) for IPv6, the string
|
||||
// "local" for a local address, and the string "unroutable" for an unroutable
|
||||
// address.
|
||||
func (am *AddressManager) GroupKey(na *appmessage.NetAddress) string {
|
||||
func (am *AddressManager) GroupKey(na *domainmessage.NetAddress) string {
|
||||
if IsLocal(na) {
|
||||
return "local"
|
||||
}
|
||||
@@ -5,9 +5,10 @@
|
||||
package addressmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
)
|
||||
|
||||
// TestIPTypes ensures the various functions which determine the type of an IP
|
||||
@@ -16,7 +17,7 @@ func TestIPTypes(t *testing.T) {
|
||||
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil)
|
||||
defer teardown()
|
||||
type ipTest struct {
|
||||
in appmessage.NetAddress
|
||||
in domainmessage.NetAddress
|
||||
rfc1918 bool
|
||||
rfc2544 bool
|
||||
rfc3849 bool
|
||||
@@ -39,7 +40,7 @@ func TestIPTypes(t *testing.T) {
|
||||
rfc4193, rfc4380, rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598,
|
||||
local, valid, routable bool) ipTest {
|
||||
nip := net.ParseIP(ip)
|
||||
na := *appmessage.NewNetAddressIPPort(nip, 16111, appmessage.SFNodeNetwork)
|
||||
na := *domainmessage.NewNetAddressIPPort(nip, 16111, domainmessage.SFNodeNetwork)
|
||||
test := ipTest{na, rfc1918, rfc2544, rfc3849, rfc3927, rfc3964, rfc4193, rfc4380,
|
||||
rfc4843, rfc4862, rfc5737, rfc6052, rfc6145, rfc6598, local, valid, routable}
|
||||
return test
|
||||
@@ -195,7 +196,7 @@ func TestGroupKey(t *testing.T) {
|
||||
|
||||
for i, test := range tests {
|
||||
nip := net.ParseIP(test.ip)
|
||||
na := *appmessage.NewNetAddressIPPort(nip, 8333, appmessage.SFNodeNetwork)
|
||||
na := *domainmessage.NewNetAddressIPPort(nip, 8333, domainmessage.SFNodeNetwork)
|
||||
if key := amgr.GroupKey(&na); key != test.expected {
|
||||
t.Errorf("TestGroupKey #%d (%s): unexpected group key "+
|
||||
"- got '%s', want '%s'", i, test.name,
|
||||
172
app/app.go
172
app/app.go
@@ -4,32 +4,34 @@ import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/netadapter/id"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/app/rpc"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag/indexers"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/domain/mining"
|
||||
"github.com/kaspanet/kaspad/domain/txscript"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/dnsseed"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/blockdag/indexers"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/connmanager"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/dnsseed"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/mempool"
|
||||
"github.com/kaspanet/kaspad/mining"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/protocol"
|
||||
"github.com/kaspanet/kaspad/rpc"
|
||||
"github.com/kaspanet/kaspad/signal"
|
||||
"github.com/kaspanet/kaspad/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
// App is a wrapper for all the kaspad services
|
||||
type App struct {
|
||||
cfg *config.Config
|
||||
rpcServer *rpc.Server
|
||||
addressManager *addressmanager.AddressManager
|
||||
protocolManager *protocol.Manager
|
||||
rpcManager *rpc.Manager
|
||||
connectionManager *connmanager.ConnectionManager
|
||||
netAdapter *netadapter.NetAdapter
|
||||
|
||||
@@ -45,39 +47,46 @@ func (a *App) Start() {
|
||||
|
||||
log.Trace("Starting kaspad")
|
||||
|
||||
err := a.netAdapter.Start()
|
||||
err := a.protocolManager.Start()
|
||||
if err != nil {
|
||||
panics.Exit(log, fmt.Sprintf("Error starting the net adapter: %+v", err))
|
||||
panics.Exit(log, fmt.Sprintf("Error starting the p2p protocol: %+v", err))
|
||||
}
|
||||
|
||||
a.maybeSeedFromDNS()
|
||||
|
||||
a.connectionManager.Start()
|
||||
|
||||
if !a.cfg.DisableRPC {
|
||||
a.rpcServer.Start()
|
||||
}
|
||||
}
|
||||
|
||||
// Stop gracefully shuts down all the kaspad services.
|
||||
func (a *App) Stop() {
|
||||
func (a *App) Stop() error {
|
||||
// Make sure this only happens once.
|
||||
if atomic.AddInt32(&a.shutdown, 1) != 1 {
|
||||
log.Infof("Kaspad is already in the process of shutting down")
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Warnf("Kaspad shutting down")
|
||||
|
||||
a.connectionManager.Stop()
|
||||
|
||||
err := a.netAdapter.Stop()
|
||||
err := a.protocolManager.Stop()
|
||||
if err != nil {
|
||||
log.Errorf("Error stopping the net adapter: %+v", err)
|
||||
log.Errorf("Error stopping the p2p protocol: %+v", err)
|
||||
}
|
||||
|
||||
err = a.addressManager.Stop()
|
||||
if err != nil {
|
||||
log.Errorf("Error stopping address manager: %s", err)
|
||||
// Shutdown the RPC server if it's not disabled.
|
||||
if !a.cfg.DisableRPC {
|
||||
err := a.rpcServer.Stop()
|
||||
if err != nil {
|
||||
log.Errorf("Error stopping rpcServer: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// New returns a new App instance configured to listen on addr for the
|
||||
@@ -100,85 +109,43 @@ func New(cfg *config.Config, databaseContext *dbaccess.DatabaseContext, interrup
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addressManager, err := addressmanager.New(cfg, databaseContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addressManager := addressmanager.New(cfg, databaseContext)
|
||||
|
||||
connectionManager, err := connmanager.New(cfg, netAdapter, addressManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protocolManager, err := protocol.NewManager(cfg, dag, netAdapter, addressManager, txMempool, connectionManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rpcManager := setupRPC(cfg, txMempool, dag, sigCache, netAdapter, protocolManager, connectionManager, addressManager, acceptanceIndex)
|
||||
rpcServer, err := setupRPC(
|
||||
cfg, dag, txMempool, sigCache, acceptanceIndex, connectionManager, addressManager, protocolManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &App{
|
||||
cfg: cfg,
|
||||
rpcServer: rpcServer,
|
||||
protocolManager: protocolManager,
|
||||
rpcManager: rpcManager,
|
||||
connectionManager: connectionManager,
|
||||
netAdapter: netAdapter,
|
||||
addressManager: addressManager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func setupRPC(
|
||||
cfg *config.Config,
|
||||
txMempool *mempool.TxPool,
|
||||
dag *blockdag.BlockDAG,
|
||||
sigCache *txscript.SigCache,
|
||||
netAdapter *netadapter.NetAdapter,
|
||||
protocolManager *protocol.Manager,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
acceptanceIndex *indexers.AcceptanceIndex) *rpc.Manager {
|
||||
|
||||
blockTemplateGenerator := mining.NewBlkTmplGenerator(&mining.Policy{BlockMaxMass: cfg.BlockMaxMass}, txMempool, dag, sigCache)
|
||||
rpcManager := rpc.NewManager(cfg, netAdapter, dag, protocolManager, connectionManager, blockTemplateGenerator, txMempool, addressManager, acceptanceIndex)
|
||||
protocolManager.SetOnBlockAddedToDAGHandler(rpcManager.NotifyBlockAddedToDAG)
|
||||
protocolManager.SetOnTransactionAddedToMempoolHandler(rpcManager.NotifyTransactionAddedToMempool)
|
||||
dag.Subscribe(func(notification *blockdag.Notification) {
|
||||
err := handleBlockDAGNotifications(notification, acceptanceIndex, rpcManager)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
return rpcManager
|
||||
}
|
||||
|
||||
func handleBlockDAGNotifications(notification *blockdag.Notification,
|
||||
acceptanceIndex *indexers.AcceptanceIndex, rpcManager *rpc.Manager) error {
|
||||
|
||||
if notification.Type == blockdag.NTChainChanged && acceptanceIndex != nil {
|
||||
chainChangedNotificationData := notification.Data.(*blockdag.ChainChangedNotificationData)
|
||||
err := rpcManager.NotifyChainChanged(chainChangedNotificationData.RemovedChainBlockHashes,
|
||||
chainChangedNotificationData.AddedChainBlockHashes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) maybeSeedFromDNS() {
|
||||
if !a.cfg.DisableDNSSeed {
|
||||
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, appmessage.SFNodeNetwork, false, nil,
|
||||
a.cfg.Lookup, func(addresses []*appmessage.NetAddress) {
|
||||
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, domainmessage.SFNodeNetwork, false, nil,
|
||||
a.cfg.Lookup, func(addresses []*domainmessage.NetAddress) {
|
||||
// Kaspad uses a lookup of the dns seeder here. Since seeder returns
|
||||
// IPs of nodes and not its own IP, we can not know real IP of
|
||||
// source. So we'll take first returned address as source.
|
||||
a.addressManager.AddAddresses(addresses, addresses[0], nil)
|
||||
})
|
||||
}
|
||||
|
||||
if a.cfg.GRPCSeed != "" {
|
||||
dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil,
|
||||
func(addresses []*appmessage.NetAddress) {
|
||||
a.addressManager.AddAddresses(addresses, addresses[0], nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
func setupDAG(cfg *config.Config, databaseContext *dbaccess.DatabaseContext, interrupt <-chan struct{},
|
||||
sigCache *txscript.SigCache, indexManager blockdag.IndexManager) (*blockdag.BlockDAG, error) {
|
||||
@@ -222,14 +189,49 @@ func setupMempool(cfg *config.Config, dag *blockdag.BlockDAG, sigCache *txscript
|
||||
MinRelayTxFee: cfg.MinRelayTxFee,
|
||||
MaxTxVersion: 1,
|
||||
},
|
||||
CalcTxSequenceLockFromReferencedUTXOEntries: dag.CalcTxSequenceLockFromReferencedUTXOEntries,
|
||||
SigCache: sigCache,
|
||||
DAG: dag,
|
||||
CalcSequenceLockNoLock: func(tx *util.Tx, utxoSet blockdag.UTXOSet) (*blockdag.SequenceLock, error) {
|
||||
return dag.CalcSequenceLockNoLock(tx, utxoSet, true)
|
||||
},
|
||||
IsDeploymentActive: dag.IsDeploymentActive,
|
||||
SigCache: sigCache,
|
||||
DAG: dag,
|
||||
}
|
||||
|
||||
return mempool.New(&mempoolConfig)
|
||||
}
|
||||
|
||||
func setupRPC(cfg *config.Config,
|
||||
dag *blockdag.BlockDAG,
|
||||
txMempool *mempool.TxPool,
|
||||
sigCache *txscript.SigCache,
|
||||
acceptanceIndex *indexers.AcceptanceIndex,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
protocolManager *protocol.Manager) (*rpc.Server, error) {
|
||||
|
||||
if !cfg.DisableRPC {
|
||||
policy := mining.Policy{
|
||||
BlockMaxMass: cfg.BlockMaxMass,
|
||||
}
|
||||
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy, txMempool, dag, sigCache)
|
||||
|
||||
rpcServer, err := rpc.NewRPCServer(cfg, dag, txMempool, acceptanceIndex, blockTemplateGenerator,
|
||||
connectionManager, addressManager, protocolManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Signal process shutdown when the RPC server requests it.
|
||||
spawn("setupRPC-handleShutdownRequest", func() {
|
||||
<-rpcServer.RequestedProcessShutdown()
|
||||
signal.ShutdownRequestChannel <- struct{}{}
|
||||
})
|
||||
|
||||
return rpcServer, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// P2PNodeID returns the network ID associated with this App
|
||||
func (a *App) P2PNodeID() *id.ID {
|
||||
return a.netAdapter.ID()
|
||||
@@ -239,3 +241,9 @@ func (a *App) P2PNodeID() *id.ID {
|
||||
func (a *App) AddressManager() *addressmanager.AddressManager {
|
||||
return a.addressManager
|
||||
}
|
||||
|
||||
// WaitForShutdown blocks until the main listener and peer handlers are stopped.
|
||||
func (a *App) WaitForShutdown() {
|
||||
// TODO(libp2p)
|
||||
// a.p2pServer.WaitForShutdown()
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
import "time"
|
||||
|
||||
type baseMessage struct {
|
||||
messageNumber uint64
|
||||
receivedAt time.Time
|
||||
}
|
||||
|
||||
func (b *baseMessage) MessageNumber() uint64 {
|
||||
return b.messageNumber
|
||||
}
|
||||
|
||||
func (b *baseMessage) SetMessageNumber(messageNumber uint64) {
|
||||
b.messageNumber = messageNumber
|
||||
}
|
||||
|
||||
func (b *baseMessage) ReceivedAt() time.Time {
|
||||
return b.receivedAt
|
||||
}
|
||||
|
||||
func (b *baseMessage) SetReceivedAt(receivedAt time.Time) {
|
||||
b.receivedAt = receivedAt
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MaxMessagePayload is the maximum bytes a message can be regardless of other
|
||||
// individual limits imposed by messages themselves.
|
||||
const MaxMessagePayload = (1024 * 1024 * 32) // 32MB
|
||||
|
||||
// MessageCommand is a number in the header of a message that represents its type.
|
||||
type MessageCommand uint32
|
||||
|
||||
func (cmd MessageCommand) String() string {
|
||||
cmdString, ok := ProtocolMessageCommandToString[cmd]
|
||||
if !ok {
|
||||
cmdString, ok = RPCMessageCommandToString[cmd]
|
||||
}
|
||||
if !ok {
|
||||
cmdString = "unknown command"
|
||||
}
|
||||
return fmt.Sprintf("%s [code %d]", cmdString, uint8(cmd))
|
||||
}
|
||||
|
||||
// Commands used in kaspa message headers which describe the type of message.
|
||||
const (
|
||||
// protocol
|
||||
CmdVersion MessageCommand = iota
|
||||
CmdVerAck
|
||||
CmdRequestAddresses
|
||||
CmdAddresses
|
||||
CmdRequestIBDBlocks
|
||||
CmdBlock
|
||||
CmdTx
|
||||
CmdPing
|
||||
CmdPong
|
||||
CmdRequestBlockLocator
|
||||
CmdBlockLocator
|
||||
CmdSelectedTip
|
||||
CmdRequestSelectedTip
|
||||
CmdInvRelayBlock
|
||||
CmdRequestRelayBlocks
|
||||
CmdInvTransaction
|
||||
CmdRequestTransactions
|
||||
CmdIBDBlock
|
||||
CmdRequestNextIBDBlocks
|
||||
CmdDoneIBDBlocks
|
||||
CmdTransactionNotFound
|
||||
CmdReject
|
||||
|
||||
// rpc
|
||||
CmdGetCurrentNetworkRequestMessage
|
||||
CmdGetCurrentNetworkResponseMessage
|
||||
CmdSubmitBlockRequestMessage
|
||||
CmdSubmitBlockResponseMessage
|
||||
CmdGetBlockTemplateRequestMessage
|
||||
CmdGetBlockTemplateResponseMessage
|
||||
CmdGetBlockTemplateTransactionMessage
|
||||
CmdNotifyBlockAddedRequestMessage
|
||||
CmdNotifyBlockAddedResponseMessage
|
||||
CmdBlockAddedNotificationMessage
|
||||
CmdGetPeerAddressesRequestMessage
|
||||
CmdGetPeerAddressesResponseMessage
|
||||
CmdGetSelectedTipHashRequestMessage
|
||||
CmdGetSelectedTipHashResponseMessage
|
||||
CmdGetMempoolEntryRequestMessage
|
||||
CmdGetMempoolEntryResponseMessage
|
||||
CmdGetConnectedPeerInfoRequestMessage
|
||||
CmdGetConnectedPeerInfoResponseMessage
|
||||
CmdAddPeerRequestMessage
|
||||
CmdAddPeerResponseMessage
|
||||
CmdSubmitTransactionRequestMessage
|
||||
CmdSubmitTransactionResponseMessage
|
||||
CmdNotifyChainChangedRequestMessage
|
||||
CmdNotifyChainChangedResponseMessage
|
||||
CmdChainChangedNotificationMessage
|
||||
CmdGetBlockRequestMessage
|
||||
CmdGetBlockResponseMessage
|
||||
CmdGetSubnetworkRequestMessage
|
||||
CmdGetSubnetworkResponseMessage
|
||||
CmdGetChainFromBlockRequestMessage
|
||||
CmdGetChainFromBlockResponseMessage
|
||||
CmdGetBlocksRequestMessage
|
||||
CmdGetBlocksResponseMessage
|
||||
CmdGetBlockCountRequestMessage
|
||||
CmdGetBlockCountResponseMessage
|
||||
CmdGetBlockDAGInfoRequestMessage
|
||||
CmdGetBlockDAGInfoResponseMessage
|
||||
CmdGetHeadersRequestMessage
|
||||
CmdGetHeadersResponseMessage
|
||||
)
|
||||
|
||||
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
||||
var ProtocolMessageCommandToString = map[MessageCommand]string{
|
||||
CmdVersion: "Version",
|
||||
CmdVerAck: "VerAck",
|
||||
CmdRequestAddresses: "RequestAddresses",
|
||||
CmdAddresses: "Addresses",
|
||||
CmdRequestIBDBlocks: "RequestBlocks",
|
||||
CmdBlock: "Block",
|
||||
CmdTx: "Tx",
|
||||
CmdPing: "Ping",
|
||||
CmdPong: "Pong",
|
||||
CmdRequestBlockLocator: "RequestBlockLocator",
|
||||
CmdBlockLocator: "BlockLocator",
|
||||
CmdSelectedTip: "SelectedTip",
|
||||
CmdRequestSelectedTip: "RequestSelectedTip",
|
||||
CmdInvRelayBlock: "InvRelayBlock",
|
||||
CmdRequestRelayBlocks: "RequestRelayBlocks",
|
||||
CmdInvTransaction: "InvTransaction",
|
||||
CmdRequestTransactions: "RequestTransactions",
|
||||
CmdIBDBlock: "IBDBlock",
|
||||
CmdRequestNextIBDBlocks: "RequestNextIBDBlocks",
|
||||
CmdDoneIBDBlocks: "DoneIBDBlocks",
|
||||
CmdTransactionNotFound: "TransactionNotFound",
|
||||
CmdReject: "Reject",
|
||||
}
|
||||
|
||||
// RPCMessageCommandToString maps all MessageCommands to their string representation
|
||||
var RPCMessageCommandToString = map[MessageCommand]string{
|
||||
CmdGetCurrentNetworkRequestMessage: "GetCurrentNetworkRequest",
|
||||
CmdGetCurrentNetworkResponseMessage: "GetCurrentNetworkResponse",
|
||||
CmdSubmitBlockRequestMessage: "SubmitBlockRequest",
|
||||
CmdSubmitBlockResponseMessage: "SubmitBlockResponse",
|
||||
CmdGetBlockTemplateRequestMessage: "GetBlockTemplateRequest",
|
||||
CmdGetBlockTemplateResponseMessage: "GetBlockTemplateResponse",
|
||||
CmdGetBlockTemplateTransactionMessage: "CmdGetBlockTemplateTransaction",
|
||||
CmdNotifyBlockAddedRequestMessage: "NotifyBlockAddedRequest",
|
||||
CmdNotifyBlockAddedResponseMessage: "NotifyBlockAddedResponse",
|
||||
CmdBlockAddedNotificationMessage: "BlockAddedNotification",
|
||||
CmdGetPeerAddressesRequestMessage: "GetPeerAddressesRequest",
|
||||
CmdGetPeerAddressesResponseMessage: "GetPeerAddressesResponse",
|
||||
CmdGetSelectedTipHashRequestMessage: "GetSelectedTipHashRequest",
|
||||
CmdGetSelectedTipHashResponseMessage: "GetSelectedTipHashResponse",
|
||||
CmdGetMempoolEntryRequestMessage: "GetMempoolEntryRequest",
|
||||
CmdGetMempoolEntryResponseMessage: "GetMempoolEntryResponse",
|
||||
CmdGetConnectedPeerInfoRequestMessage: "GetConnectedPeerInfoRequest",
|
||||
CmdGetConnectedPeerInfoResponseMessage: "GetConnectedPeerInfoResponse",
|
||||
CmdAddPeerRequestMessage: "AddPeerRequest",
|
||||
CmdAddPeerResponseMessage: "AddPeerResponse",
|
||||
CmdSubmitTransactionRequestMessage: "SubmitTransactionRequest",
|
||||
CmdSubmitTransactionResponseMessage: "SubmitTransactionResponse",
|
||||
CmdNotifyChainChangedRequestMessage: "NotifyChainChangedRequest",
|
||||
CmdNotifyChainChangedResponseMessage: "NotifyChainChangedResponse",
|
||||
CmdChainChangedNotificationMessage: "ChainChangedNotification",
|
||||
CmdGetBlockRequestMessage: "GetBlockRequest",
|
||||
CmdGetBlockResponseMessage: "GetBlockResponse",
|
||||
CmdGetSubnetworkRequestMessage: "GetSubnetworkRequest",
|
||||
CmdGetSubnetworkResponseMessage: "GetSubnetworkResponse",
|
||||
CmdGetChainFromBlockRequestMessage: "GetChainFromBlockRequest",
|
||||
CmdGetChainFromBlockResponseMessage: "GetChainFromBlockResponse",
|
||||
CmdGetBlocksRequestMessage: "GetBlocksRequest",
|
||||
CmdGetBlocksResponseMessage: "GetBlocksResponse",
|
||||
CmdGetBlockCountRequestMessage: "GetBlockCountRequest",
|
||||
CmdGetBlockCountResponseMessage: "GetBlockCountResponse",
|
||||
CmdGetBlockDAGInfoRequestMessage: "GetBlockDAGInfoRequest",
|
||||
CmdGetBlockDAGInfoResponseMessage: "GetBlockDAGInfoResponse",
|
||||
CmdGetHeadersRequestMessage: "GetHeadersRequest",
|
||||
CmdGetHeadersResponseMessage: "GetHeadersResponse",
|
||||
}
|
||||
|
||||
// Message is an interface that describes a kaspa message. A type that
|
||||
// implements Message has complete control over the representation of its data
|
||||
// and may therefore contain additional or fewer fields than those which
|
||||
// are used directly in the protocol encoded message.
|
||||
type Message interface {
|
||||
Command() MessageCommand
|
||||
MessageNumber() uint64
|
||||
SetMessageNumber(index uint64)
|
||||
ReceivedAt() time.Time
|
||||
SetReceivedAt(receivedAt time.Time)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// MsgReject implements the Message interface and represents a kaspa
|
||||
// Reject message. It is used to notify peers why they are banned.
|
||||
type MsgReject struct {
|
||||
baseMessage
|
||||
Reason string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
func (msg *MsgReject) Command() MessageCommand {
|
||||
return CmdReject
|
||||
}
|
||||
|
||||
// NewMsgReject returns a new kaspa Reject message that conforms to the
|
||||
// Message interface.
|
||||
func NewMsgReject(reason string) *MsgReject {
|
||||
return &MsgReject{
|
||||
Reason: reason,
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// AddPeerRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type AddPeerRequestMessage struct {
|
||||
baseMessage
|
||||
Address string
|
||||
IsPermanent bool
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *AddPeerRequestMessage) Command() MessageCommand {
|
||||
return CmdAddPeerRequestMessage
|
||||
}
|
||||
|
||||
// NewAddPeerRequestMessage returns a instance of the message
|
||||
func NewAddPeerRequestMessage(address string, isPermanent bool) *AddPeerRequestMessage {
|
||||
return &AddPeerRequestMessage{
|
||||
Address: address,
|
||||
IsPermanent: isPermanent,
|
||||
}
|
||||
}
|
||||
|
||||
// AddPeerResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type AddPeerResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *AddPeerResponseMessage) Command() MessageCommand {
|
||||
return CmdAddPeerResponseMessage
|
||||
}
|
||||
|
||||
// NewAddPeerResponseMessage returns a instance of the message
|
||||
func NewAddPeerResponseMessage() *AddPeerResponseMessage {
|
||||
return &AddPeerResponseMessage{}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetBlockRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockRequestMessage struct {
|
||||
baseMessage
|
||||
Hash string
|
||||
SubnetworkID string
|
||||
IncludeBlockHex bool
|
||||
IncludeBlockVerboseData bool
|
||||
IncludeTransactionVerboseData bool
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockRequestMessage) Command() MessageCommand {
|
||||
return CmdGetBlockRequestMessage
|
||||
}
|
||||
|
||||
// NewGetBlockRequestMessage returns a instance of the message
|
||||
func NewGetBlockRequestMessage(hash string, subnetworkID string, includeBlockHex bool,
|
||||
includeBlockVerboseData bool, includeTransactionVerboseData bool) *GetBlockRequestMessage {
|
||||
return &GetBlockRequestMessage{
|
||||
Hash: hash,
|
||||
SubnetworkID: subnetworkID,
|
||||
IncludeBlockHex: includeBlockHex,
|
||||
IncludeBlockVerboseData: includeBlockVerboseData,
|
||||
IncludeTransactionVerboseData: includeTransactionVerboseData,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlockResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockResponseMessage struct {
|
||||
baseMessage
|
||||
BlockHex string
|
||||
BlockVerboseData *BlockVerboseData
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockResponseMessage) Command() MessageCommand {
|
||||
return CmdGetBlockResponseMessage
|
||||
}
|
||||
|
||||
// NewGetBlockResponseMessage returns a instance of the message
|
||||
func NewGetBlockResponseMessage() *GetBlockResponseMessage {
|
||||
return &GetBlockResponseMessage{}
|
||||
}
|
||||
|
||||
// BlockVerboseData holds verbose data about a block
|
||||
type BlockVerboseData struct {
|
||||
Hash string
|
||||
Confirmations uint64
|
||||
Size int32
|
||||
BlueScore uint64
|
||||
IsChainBlock bool
|
||||
Version int32
|
||||
VersionHex string
|
||||
HashMerkleRoot string
|
||||
AcceptedIDMerkleRoot string
|
||||
UTXOCommitment string
|
||||
TxIDs []string
|
||||
TransactionVerboseData []*TransactionVerboseData
|
||||
Time int64
|
||||
Nonce uint64
|
||||
Bits string
|
||||
Difficulty float64
|
||||
ParentHashes []string
|
||||
SelectedParentHash string
|
||||
ChildHashes []string
|
||||
AcceptedBlockHashes []string
|
||||
}
|
||||
|
||||
// TransactionVerboseData holds verbose data about a transaction
|
||||
type TransactionVerboseData struct {
|
||||
Hex string
|
||||
TxID string
|
||||
Hash string
|
||||
Size int32
|
||||
Version int32
|
||||
LockTime uint64
|
||||
SubnetworkID string
|
||||
Gas uint64
|
||||
PayloadHash string
|
||||
Payload string
|
||||
TransactionVerboseInputs []*TransactionVerboseInput
|
||||
TransactionVerboseOutputs []*TransactionVerboseOutput
|
||||
BlockHash string
|
||||
AcceptedBy string
|
||||
IsInMempool bool
|
||||
Time uint64
|
||||
BlockTime uint64
|
||||
}
|
||||
|
||||
// TransactionVerboseInput holds data about a transaction input
|
||||
type TransactionVerboseInput struct {
|
||||
TxID string
|
||||
OutputIndex uint32
|
||||
ScriptSig *ScriptSig
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
// ScriptSig holds data about a script signature
|
||||
type ScriptSig struct {
|
||||
Asm string
|
||||
Hex string
|
||||
}
|
||||
|
||||
// TransactionVerboseOutput holds data about a transaction output
|
||||
type TransactionVerboseOutput struct {
|
||||
Value uint64
|
||||
Index uint32
|
||||
ScriptPubKey *ScriptPubKeyResult
|
||||
}
|
||||
|
||||
// ScriptPubKeyResult holds data about a script public key
|
||||
type ScriptPubKeyResult struct {
|
||||
Asm string
|
||||
Hex string
|
||||
Type string
|
||||
Address string
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetBlockCountRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockCountRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockCountRequestMessage) Command() MessageCommand {
|
||||
return CmdGetBlockCountRequestMessage
|
||||
}
|
||||
|
||||
// NewGetBlockCountRequestMessage returns a instance of the message
|
||||
func NewGetBlockCountRequestMessage() *GetBlockCountRequestMessage {
|
||||
return &GetBlockCountRequestMessage{}
|
||||
}
|
||||
|
||||
// GetBlockCountResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockCountResponseMessage struct {
|
||||
baseMessage
|
||||
BlockCount uint64
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockCountResponseMessage) Command() MessageCommand {
|
||||
return CmdGetBlockCountResponseMessage
|
||||
}
|
||||
|
||||
// NewGetBlockCountResponseMessage returns a instance of the message
|
||||
func NewGetBlockCountResponseMessage(blockCount uint64) *GetBlockCountResponseMessage {
|
||||
return &GetBlockCountResponseMessage{
|
||||
BlockCount: blockCount,
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetBlockDAGInfoRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockDAGInfoRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockDAGInfoRequestMessage) Command() MessageCommand {
|
||||
return CmdGetBlockDAGInfoRequestMessage
|
||||
}
|
||||
|
||||
// NewGetBlockDAGInfoRequestMessage returns a instance of the message
|
||||
func NewGetBlockDAGInfoRequestMessage() *GetBlockDAGInfoRequestMessage {
|
||||
return &GetBlockDAGInfoRequestMessage{}
|
||||
}
|
||||
|
||||
// GetBlockDAGInfoResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockDAGInfoResponseMessage struct {
|
||||
baseMessage
|
||||
NetworkName string
|
||||
BlockCount uint64
|
||||
TipHashes []string
|
||||
Difficulty float64
|
||||
PastMedianTime int64
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockDAGInfoResponseMessage) Command() MessageCommand {
|
||||
return CmdGetBlockDAGInfoResponseMessage
|
||||
}
|
||||
|
||||
// NewGetBlockDAGInfoResponseMessage returns a instance of the message
|
||||
func NewGetBlockDAGInfoResponseMessage() *GetBlockDAGInfoResponseMessage {
|
||||
return &GetBlockDAGInfoResponseMessage{}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetBlockTemplateRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockTemplateRequestMessage struct {
|
||||
baseMessage
|
||||
PayAddress string
|
||||
LongPollID string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockTemplateRequestMessage) Command() MessageCommand {
|
||||
return CmdGetBlockTemplateRequestMessage
|
||||
}
|
||||
|
||||
// NewGetBlockTemplateRequestMessage returns a instance of the message
|
||||
func NewGetBlockTemplateRequestMessage(payAddress string, longPollID string) *GetBlockTemplateRequestMessage {
|
||||
return &GetBlockTemplateRequestMessage{
|
||||
PayAddress: payAddress,
|
||||
LongPollID: longPollID,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlockTemplateResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockTemplateResponseMessage struct {
|
||||
baseMessage
|
||||
Bits string
|
||||
CurrentTime int64
|
||||
ParentHashes []string
|
||||
MassLimit int
|
||||
Transactions []GetBlockTemplateTransactionMessage
|
||||
HashMerkleRoot string
|
||||
AcceptedIDMerkleRoot string
|
||||
UTXOCommitment string
|
||||
Version int32
|
||||
LongPollID string
|
||||
TargetDifficulty string
|
||||
MinTime int64
|
||||
MaxTime int64
|
||||
MutableFields []string
|
||||
NonceRange string
|
||||
IsSynced bool
|
||||
IsConnected bool
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockTemplateResponseMessage) Command() MessageCommand {
|
||||
return CmdGetBlockTemplateResponseMessage
|
||||
}
|
||||
|
||||
// NewGetBlockTemplateResponseMessage returns a instance of the message
|
||||
func NewGetBlockTemplateResponseMessage() *GetBlockTemplateResponseMessage {
|
||||
return &GetBlockTemplateResponseMessage{}
|
||||
}
|
||||
|
||||
// GetBlockTemplateTransactionMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlockTemplateTransactionMessage struct {
|
||||
baseMessage
|
||||
Data string
|
||||
ID string
|
||||
Depends []int64
|
||||
Mass uint64
|
||||
Fee uint64
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlockTemplateTransactionMessage) Command() MessageCommand {
|
||||
return CmdGetBlockTemplateTransactionMessage
|
||||
}
|
||||
|
||||
// NewGetBlockTemplateTransactionMessage returns a instance of the message
|
||||
func NewGetBlockTemplateTransactionMessage() *GetBlockTemplateTransactionMessage {
|
||||
return &GetBlockTemplateTransactionMessage{}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetBlocksRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlocksRequestMessage struct {
|
||||
baseMessage
|
||||
LowHash string
|
||||
IncludeBlockHexes bool
|
||||
IncludeBlockVerboseData bool
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlocksRequestMessage) Command() MessageCommand {
|
||||
return CmdGetBlocksRequestMessage
|
||||
}
|
||||
|
||||
// NewGetBlocksRequestMessage returns a instance of the message
|
||||
func NewGetBlocksRequestMessage(lowHash string, includeBlockHexes bool, includeBlockVerboseData bool) *GetBlocksRequestMessage {
|
||||
return &GetBlocksRequestMessage{
|
||||
LowHash: lowHash,
|
||||
IncludeBlockHexes: includeBlockHexes,
|
||||
IncludeBlockVerboseData: includeBlockVerboseData,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBlocksResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetBlocksResponseMessage struct {
|
||||
baseMessage
|
||||
BlockHashes []string
|
||||
BlockHexes []string
|
||||
BlockVerboseData []*BlockVerboseData
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetBlocksResponseMessage) Command() MessageCommand {
|
||||
return CmdGetBlocksResponseMessage
|
||||
}
|
||||
|
||||
// NewGetBlocksResponseMessage returns a instance of the message
|
||||
func NewGetBlocksResponseMessage(blockHashes []string, blockHexes []string,
|
||||
blockVerboseData []*BlockVerboseData) *GetBlocksResponseMessage {
|
||||
|
||||
return &GetBlocksResponseMessage{
|
||||
BlockHashes: blockHashes,
|
||||
BlockHexes: blockHexes,
|
||||
BlockVerboseData: blockVerboseData,
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetChainFromBlockRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetChainFromBlockRequestMessage struct {
|
||||
baseMessage
|
||||
StartHash string
|
||||
IncludeBlockVerboseData bool
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetChainFromBlockRequestMessage) Command() MessageCommand {
|
||||
return CmdGetChainFromBlockRequestMessage
|
||||
}
|
||||
|
||||
// NewGetChainFromBlockRequestMessage returns a instance of the message
|
||||
func NewGetChainFromBlockRequestMessage(startHash string, includeBlockVerboseData bool) *GetChainFromBlockRequestMessage {
|
||||
return &GetChainFromBlockRequestMessage{
|
||||
StartHash: startHash,
|
||||
IncludeBlockVerboseData: includeBlockVerboseData,
|
||||
}
|
||||
}
|
||||
|
||||
// GetChainFromBlockResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetChainFromBlockResponseMessage struct {
|
||||
baseMessage
|
||||
RemovedChainBlockHashes []string
|
||||
AddedChainBlocks []*ChainBlock
|
||||
BlockVerboseData []*BlockVerboseData
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetChainFromBlockResponseMessage) Command() MessageCommand {
|
||||
return CmdGetChainFromBlockResponseMessage
|
||||
}
|
||||
|
||||
// NewGetChainFromBlockResponseMessage returns a instance of the message
|
||||
func NewGetChainFromBlockResponseMessage(removedChainBlockHashes []string,
|
||||
addedChainBlocks []*ChainBlock, blockVerboseData []*BlockVerboseData) *GetChainFromBlockResponseMessage {
|
||||
|
||||
return &GetChainFromBlockResponseMessage{
|
||||
RemovedChainBlockHashes: removedChainBlockHashes,
|
||||
AddedChainBlocks: addedChainBlocks,
|
||||
BlockVerboseData: blockVerboseData,
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetConnectedPeerInfoRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetConnectedPeerInfoRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetConnectedPeerInfoRequestMessage) Command() MessageCommand {
|
||||
return CmdGetConnectedPeerInfoRequestMessage
|
||||
}
|
||||
|
||||
// NewGetConnectedPeerInfoRequestMessage returns a instance of the message
|
||||
func NewGetConnectedPeerInfoRequestMessage() *GetConnectedPeerInfoRequestMessage {
|
||||
return &GetConnectedPeerInfoRequestMessage{}
|
||||
}
|
||||
|
||||
// GetConnectedPeerInfoResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetConnectedPeerInfoResponseMessage struct {
|
||||
baseMessage
|
||||
Infos []*GetConnectedPeerInfoMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetConnectedPeerInfoResponseMessage) Command() MessageCommand {
|
||||
return CmdGetConnectedPeerInfoResponseMessage
|
||||
}
|
||||
|
||||
// NewGetConnectedPeerInfoResponseMessage returns a instance of the message
|
||||
func NewGetConnectedPeerInfoResponseMessage(infos []*GetConnectedPeerInfoMessage) *GetConnectedPeerInfoResponseMessage {
|
||||
return &GetConnectedPeerInfoResponseMessage{
|
||||
Infos: infos,
|
||||
}
|
||||
}
|
||||
|
||||
// GetConnectedPeerInfoMessage holds information about a connected peer
|
||||
type GetConnectedPeerInfoMessage struct {
|
||||
ID string
|
||||
Address string
|
||||
LastPingDuration int64
|
||||
SelectedTipHash string
|
||||
IsSyncNode bool
|
||||
IsOutbound bool
|
||||
TimeOffset int64
|
||||
UserAgent string
|
||||
AdvertisedProtocolVersion uint32
|
||||
TimeConnected int64
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetCurrentNetworkRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetCurrentNetworkRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetCurrentNetworkRequestMessage) Command() MessageCommand {
|
||||
return CmdGetCurrentNetworkRequestMessage
|
||||
}
|
||||
|
||||
// NewGetCurrentNetworkRequestMessage returns a instance of the message
|
||||
func NewGetCurrentNetworkRequestMessage() *GetCurrentNetworkRequestMessage {
|
||||
return &GetCurrentNetworkRequestMessage{}
|
||||
}
|
||||
|
||||
// GetCurrentNetworkResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetCurrentNetworkResponseMessage struct {
|
||||
baseMessage
|
||||
CurrentNetwork string
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetCurrentNetworkResponseMessage) Command() MessageCommand {
|
||||
return CmdGetCurrentNetworkResponseMessage
|
||||
}
|
||||
|
||||
// NewGetCurrentNetworkResponseMessage returns a instance of the message
|
||||
func NewGetCurrentNetworkResponseMessage(currentNetwork string) *GetCurrentNetworkResponseMessage {
|
||||
return &GetCurrentNetworkResponseMessage{
|
||||
CurrentNetwork: currentNetwork,
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetHeadersRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetHeadersRequestMessage struct {
|
||||
baseMessage
|
||||
StartHash string
|
||||
Limit uint64
|
||||
IsAscending bool
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetHeadersRequestMessage) Command() MessageCommand {
|
||||
return CmdGetHeadersRequestMessage
|
||||
}
|
||||
|
||||
// NewGetHeadersRequestMessage returns a instance of the message
|
||||
func NewGetHeadersRequestMessage(startHash string, limit uint64, isAscending bool) *GetHeadersRequestMessage {
|
||||
return &GetHeadersRequestMessage{
|
||||
StartHash: startHash,
|
||||
Limit: limit,
|
||||
IsAscending: isAscending,
|
||||
}
|
||||
}
|
||||
|
||||
// GetHeadersResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetHeadersResponseMessage struct {
|
||||
baseMessage
|
||||
Headers []string
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetHeadersResponseMessage) Command() MessageCommand {
|
||||
return CmdGetHeadersResponseMessage
|
||||
}
|
||||
|
||||
// NewGetHeadersResponseMessage returns a instance of the message
|
||||
func NewGetHeadersResponseMessage(headers []string) *GetHeadersResponseMessage {
|
||||
return &GetHeadersResponseMessage{
|
||||
Headers: headers,
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetMempoolEntryRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetMempoolEntryRequestMessage struct {
|
||||
baseMessage
|
||||
TxID string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetMempoolEntryRequestMessage) Command() MessageCommand {
|
||||
return CmdGetMempoolEntryRequestMessage
|
||||
}
|
||||
|
||||
// NewGetMempoolEntryRequestMessage returns a instance of the message
|
||||
func NewGetMempoolEntryRequestMessage(txID string) *GetMempoolEntryRequestMessage {
|
||||
return &GetMempoolEntryRequestMessage{TxID: txID}
|
||||
}
|
||||
|
||||
// GetMempoolEntryResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetMempoolEntryResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetMempoolEntryResponseMessage) Command() MessageCommand {
|
||||
return CmdGetMempoolEntryResponseMessage
|
||||
}
|
||||
|
||||
// NewGetMempoolEntryResponseMessage returns a instance of the message
|
||||
func NewGetMempoolEntryResponseMessage() *GetMempoolEntryResponseMessage {
|
||||
return &GetMempoolEntryResponseMessage{}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetPeerAddressesRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetPeerAddressesRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetPeerAddressesRequestMessage) Command() MessageCommand {
|
||||
return CmdGetPeerAddressesRequestMessage
|
||||
}
|
||||
|
||||
// NewGetPeerAddressesRequestMessage returns a instance of the message
|
||||
func NewGetPeerAddressesRequestMessage() *GetPeerAddressesRequestMessage {
|
||||
return &GetPeerAddressesRequestMessage{}
|
||||
}
|
||||
|
||||
// GetPeerAddressesResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetPeerAddressesResponseMessage struct {
|
||||
baseMessage
|
||||
Addresses []*GetPeerAddressesKnownAddressMessage
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetPeerAddressesResponseMessage) Command() MessageCommand {
|
||||
return CmdGetPeerAddressesResponseMessage
|
||||
}
|
||||
|
||||
// NewGetPeerAddressesResponseMessage returns a instance of the message
|
||||
func NewGetPeerAddressesResponseMessage(addresses []*GetPeerAddressesKnownAddressMessage) *GetPeerAddressesResponseMessage {
|
||||
return &GetPeerAddressesResponseMessage{
|
||||
Addresses: addresses,
|
||||
}
|
||||
}
|
||||
|
||||
// GetPeerAddressesKnownAddressMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetPeerAddressesKnownAddressMessage struct {
|
||||
Addr string
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetSelectedTipHashRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetSelectedTipHashRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetSelectedTipHashRequestMessage) Command() MessageCommand {
|
||||
return CmdGetSelectedTipHashRequestMessage
|
||||
}
|
||||
|
||||
// NewGetSelectedTipHashRequestMessage returns a instance of the message
|
||||
func NewGetSelectedTipHashRequestMessage() *GetSelectedTipHashRequestMessage {
|
||||
return &GetSelectedTipHashRequestMessage{}
|
||||
}
|
||||
|
||||
// GetSelectedTipHashResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetSelectedTipHashResponseMessage struct {
|
||||
baseMessage
|
||||
SelectedTipHash string
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetSelectedTipHashResponseMessage) Command() MessageCommand {
|
||||
return CmdGetSelectedTipHashResponseMessage
|
||||
}
|
||||
|
||||
// NewGetSelectedTipHashResponseMessage returns a instance of the message
|
||||
func NewGetSelectedTipHashResponseMessage(selectedTipHash string) *GetSelectedTipHashResponseMessage {
|
||||
return &GetSelectedTipHashResponseMessage{
|
||||
SelectedTipHash: selectedTipHash,
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// GetSubnetworkRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetSubnetworkRequestMessage struct {
|
||||
baseMessage
|
||||
SubnetworkID string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetSubnetworkRequestMessage) Command() MessageCommand {
|
||||
return CmdGetSubnetworkRequestMessage
|
||||
}
|
||||
|
||||
// NewGetSubnetworkRequestMessage returns a instance of the message
|
||||
func NewGetSubnetworkRequestMessage(subnetworkID string) *GetSubnetworkRequestMessage {
|
||||
return &GetSubnetworkRequestMessage{
|
||||
SubnetworkID: subnetworkID,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSubnetworkResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type GetSubnetworkResponseMessage struct {
|
||||
baseMessage
|
||||
GasLimit uint64
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *GetSubnetworkResponseMessage) Command() MessageCommand {
|
||||
return CmdGetSubnetworkResponseMessage
|
||||
}
|
||||
|
||||
// NewGetSubnetworkResponseMessage returns a instance of the message
|
||||
func NewGetSubnetworkResponseMessage(gasLimit uint64) *GetSubnetworkResponseMessage {
|
||||
return &GetSubnetworkResponseMessage{
|
||||
GasLimit: gasLimit,
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// NotifyBlockAddedRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyBlockAddedRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyBlockAddedRequestMessage) Command() MessageCommand {
|
||||
return CmdNotifyBlockAddedRequestMessage
|
||||
}
|
||||
|
||||
// NewNotifyBlockAddedRequestMessage returns a instance of the message
|
||||
func NewNotifyBlockAddedRequestMessage() *NotifyBlockAddedRequestMessage {
|
||||
return &NotifyBlockAddedRequestMessage{}
|
||||
}
|
||||
|
||||
// NotifyBlockAddedResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyBlockAddedResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyBlockAddedResponseMessage) Command() MessageCommand {
|
||||
return CmdNotifyBlockAddedResponseMessage
|
||||
}
|
||||
|
||||
// NewNotifyBlockAddedResponseMessage returns a instance of the message
|
||||
func NewNotifyBlockAddedResponseMessage() *NotifyBlockAddedResponseMessage {
|
||||
return &NotifyBlockAddedResponseMessage{}
|
||||
}
|
||||
|
||||
// BlockAddedNotificationMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type BlockAddedNotificationMessage struct {
|
||||
baseMessage
|
||||
Block *MsgBlock
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *BlockAddedNotificationMessage) Command() MessageCommand {
|
||||
return CmdBlockAddedNotificationMessage
|
||||
}
|
||||
|
||||
// NewBlockAddedNotificationMessage returns a instance of the message
|
||||
func NewBlockAddedNotificationMessage(block *MsgBlock) *BlockAddedNotificationMessage {
|
||||
return &BlockAddedNotificationMessage{
|
||||
Block: block,
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// NotifyChainChangedRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyChainChangedRequestMessage struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyChainChangedRequestMessage) Command() MessageCommand {
|
||||
return CmdNotifyChainChangedRequestMessage
|
||||
}
|
||||
|
||||
// NewNotifyChainChangedRequestMessage returns a instance of the message
|
||||
func NewNotifyChainChangedRequestMessage() *NotifyChainChangedRequestMessage {
|
||||
return &NotifyChainChangedRequestMessage{}
|
||||
}
|
||||
|
||||
// NotifyChainChangedResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type NotifyChainChangedResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *NotifyChainChangedResponseMessage) Command() MessageCommand {
|
||||
return CmdNotifyChainChangedResponseMessage
|
||||
}
|
||||
|
||||
// NewNotifyChainChangedResponseMessage returns a instance of the message
|
||||
func NewNotifyChainChangedResponseMessage() *NotifyChainChangedResponseMessage {
|
||||
return &NotifyChainChangedResponseMessage{}
|
||||
}
|
||||
|
||||
// ChainChangedNotificationMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type ChainChangedNotificationMessage struct {
|
||||
baseMessage
|
||||
RemovedChainBlockHashes []string
|
||||
AddedChainBlocks []*ChainBlock
|
||||
}
|
||||
|
||||
// ChainBlock represents a DAG chain-block
|
||||
type ChainBlock struct {
|
||||
Hash string
|
||||
AcceptedBlocks []*AcceptedBlock
|
||||
}
|
||||
|
||||
// AcceptedBlock represents a block accepted into the DAG
|
||||
type AcceptedBlock struct {
|
||||
Hash string
|
||||
AcceptedTxIDs []string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *ChainChangedNotificationMessage) Command() MessageCommand {
|
||||
return CmdChainChangedNotificationMessage
|
||||
}
|
||||
|
||||
// NewChainChangedNotificationMessage returns a instance of the message
|
||||
func NewChainChangedNotificationMessage(removedChainBlockHashes []string,
|
||||
addedChainBlocks []*ChainBlock) *ChainChangedNotificationMessage {
|
||||
|
||||
return &ChainChangedNotificationMessage{
|
||||
RemovedChainBlockHashes: removedChainBlockHashes,
|
||||
AddedChainBlocks: addedChainBlocks,
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// SubmitBlockRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type SubmitBlockRequestMessage struct {
|
||||
baseMessage
|
||||
BlockHex string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *SubmitBlockRequestMessage) Command() MessageCommand {
|
||||
return CmdSubmitBlockRequestMessage
|
||||
}
|
||||
|
||||
// NewSubmitBlockRequestMessage returns a instance of the message
|
||||
func NewSubmitBlockRequestMessage(blockHex string) *SubmitBlockRequestMessage {
|
||||
return &SubmitBlockRequestMessage{
|
||||
BlockHex: blockHex,
|
||||
}
|
||||
}
|
||||
|
||||
// SubmitBlockResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type SubmitBlockResponseMessage struct {
|
||||
baseMessage
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *SubmitBlockResponseMessage) Command() MessageCommand {
|
||||
return CmdSubmitBlockResponseMessage
|
||||
}
|
||||
|
||||
// NewSubmitBlockResponseMessage returns a instance of the message
|
||||
func NewSubmitBlockResponseMessage() *SubmitBlockResponseMessage {
|
||||
return &SubmitBlockResponseMessage{}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package appmessage
|
||||
|
||||
// SubmitTransactionRequestMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type SubmitTransactionRequestMessage struct {
|
||||
baseMessage
|
||||
TransactionHex string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *SubmitTransactionRequestMessage) Command() MessageCommand {
|
||||
return CmdSubmitTransactionRequestMessage
|
||||
}
|
||||
|
||||
// NewSubmitTransactionRequestMessage returns a instance of the message
|
||||
func NewSubmitTransactionRequestMessage(transactionHex string) *SubmitTransactionRequestMessage {
|
||||
return &SubmitTransactionRequestMessage{
|
||||
TransactionHex: transactionHex,
|
||||
}
|
||||
}
|
||||
|
||||
// SubmitTransactionResponseMessage is an appmessage corresponding to
|
||||
// its respective RPC message
|
||||
type SubmitTransactionResponseMessage struct {
|
||||
baseMessage
|
||||
TxID string
|
||||
|
||||
Error *RPCError
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message
|
||||
func (msg *SubmitTransactionResponseMessage) Command() MessageCommand {
|
||||
return CmdSubmitTransactionResponseMessage
|
||||
}
|
||||
|
||||
// NewSubmitTransactionResponseMessage returns a instance of the message
|
||||
func NewSubmitTransactionResponseMessage(txID string) *SubmitTransactionResponseMessage {
|
||||
return &SubmitTransactionResponseMessage{
|
||||
TxID: txID,
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
)
|
||||
|
||||
// HandleError handles an error from a flow,
|
||||
// It sends the error to errChan if isStopping == 0 and increments isStopping
|
||||
//
|
||||
// If this is ErrRouteClosed - forward it to errChan
|
||||
// If this is ProtocolError - logs the error, and forward it to errChan
|
||||
// Otherwise - panics
|
||||
func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error) {
|
||||
isErrRouteClosed := errors.Is(err, router.ErrRouteClosed)
|
||||
if !isErrRouteClosed {
|
||||
if protocolErr := &(protocolerrors.ProtocolError{}); !errors.As(err, &protocolErr) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Errorf("error from %s: %+v", flowName, err)
|
||||
}
|
||||
|
||||
if atomic.AddUint32(isStopping, 1) == 1 {
|
||||
errChan <- err
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package rejects
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleRejectsContext is the interface for the context needed for the HandleRejects flow.
|
||||
type HandleRejectsContext interface {
|
||||
}
|
||||
|
||||
type handleRejectsFlow struct {
|
||||
HandleRejectsContext
|
||||
incomingRoute, outgoingRoute *router.Route
|
||||
}
|
||||
|
||||
// HandleRejects handles all reject messages coming through incomingRoute.
|
||||
// This function assumes that incomingRoute will only return MsgReject.
|
||||
func HandleRejects(context HandleRejectsContext, incomingRoute *router.Route, outgoingRoute *router.Route) error {
|
||||
flow := &handleRejectsFlow{
|
||||
HandleRejectsContext: context,
|
||||
incomingRoute: incomingRoute,
|
||||
outgoingRoute: outgoingRoute,
|
||||
}
|
||||
return flow.start()
|
||||
}
|
||||
|
||||
func (flow *handleRejectsFlow) start() error {
|
||||
message, err := flow.incomingRoute.Dequeue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rejectMessage := message.(*appmessage.MsgReject)
|
||||
|
||||
const maxReasonLength = 255
|
||||
if len(rejectMessage.Reason) > maxReasonLength {
|
||||
return protocolerrors.Errorf(false, "got reject message longer than %d", maxReasonLength)
|
||||
}
|
||||
|
||||
return protocolerrors.Errorf(false, "got reject message: `%s`", rejectMessage.Reason)
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.RPCS)
|
||||
var spawn = panics.GoroutineWrapperFunc(log)
|
||||
@@ -1,80 +0,0 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag/indexers"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/domain/mining"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
// Manager is an RPC manager
|
||||
type Manager struct {
|
||||
context *rpccontext.Context
|
||||
}
|
||||
|
||||
// NewManager creates a new RPC Manager
|
||||
func NewManager(
|
||||
cfg *config.Config,
|
||||
netAdapter *netadapter.NetAdapter,
|
||||
dag *blockdag.BlockDAG,
|
||||
protocolManager *protocol.Manager,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
blockTemplateGenerator *mining.BlkTmplGenerator,
|
||||
mempool *mempool.TxPool,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
acceptanceIndex *indexers.AcceptanceIndex) *Manager {
|
||||
|
||||
manager := Manager{
|
||||
context: rpccontext.NewContext(
|
||||
cfg,
|
||||
netAdapter,
|
||||
dag,
|
||||
protocolManager,
|
||||
connectionManager,
|
||||
blockTemplateGenerator,
|
||||
mempool,
|
||||
addressManager,
|
||||
acceptanceIndex,
|
||||
),
|
||||
}
|
||||
netAdapter.SetRPCRouterInitializer(manager.routerInitializer)
|
||||
|
||||
return &manager
|
||||
}
|
||||
|
||||
// NotifyBlockAddedToDAG notifies the manager that a block has been added to the DAG
|
||||
func (m *Manager) NotifyBlockAddedToDAG(block *util.Block) {
|
||||
m.context.BlockTemplateState.NotifyBlockAdded(block)
|
||||
|
||||
notification := appmessage.NewBlockAddedNotificationMessage(block.MsgBlock())
|
||||
m.context.NotificationManager.NotifyBlockAdded(notification)
|
||||
}
|
||||
|
||||
// NotifyChainChanged notifies the manager that the DAG's selected parent chain has changed
|
||||
func (m *Manager) NotifyChainChanged(removedChainBlockHashes []*daghash.Hash, addedChainBlockHashes []*daghash.Hash) error {
|
||||
addedChainBlocks, err := m.context.CollectChainBlocks(addedChainBlockHashes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
removedChainBlockHashStrings := make([]string, len(removedChainBlockHashes))
|
||||
for i, removedChainBlockHash := range removedChainBlockHashes {
|
||||
removedChainBlockHashStrings[i] = removedChainBlockHash.String()
|
||||
}
|
||||
notification := appmessage.NewChainChangedNotificationMessage(removedChainBlockHashStrings, addedChainBlocks)
|
||||
m.context.NotificationManager.NotifyChainChanged(notification)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyTransactionAddedToMempool notifies the manager that a transaction has been added to the mempool
|
||||
func (m *Manager) NotifyTransactionAddedToMempool() {
|
||||
m.context.BlockTemplateState.NotifyMempoolTx()
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpchandlers"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type handler func(context *rpccontext.Context, router *router.Router, request appmessage.Message) (appmessage.Message, error)
|
||||
|
||||
var handlers = map[appmessage.MessageCommand]handler{
|
||||
appmessage.CmdGetCurrentNetworkRequestMessage: rpchandlers.HandleGetCurrentNetwork,
|
||||
appmessage.CmdSubmitBlockRequestMessage: rpchandlers.HandleSubmitBlock,
|
||||
appmessage.CmdGetBlockTemplateRequestMessage: rpchandlers.HandleGetBlockTemplate,
|
||||
appmessage.CmdNotifyBlockAddedRequestMessage: rpchandlers.HandleNotifyBlockAdded,
|
||||
appmessage.CmdGetPeerAddressesRequestMessage: rpchandlers.HandleGetPeerAddresses,
|
||||
appmessage.CmdGetSelectedTipHashRequestMessage: rpchandlers.HandleGetSelectedTipHash,
|
||||
appmessage.CmdGetMempoolEntryRequestMessage: rpchandlers.HandleGetMempoolEntry,
|
||||
appmessage.CmdGetConnectedPeerInfoRequestMessage: rpchandlers.HandleGetConnectedPeerInfo,
|
||||
appmessage.CmdAddPeerRequestMessage: rpchandlers.HandleAddPeer,
|
||||
appmessage.CmdSubmitTransactionRequestMessage: rpchandlers.HandleSubmitTransaction,
|
||||
appmessage.CmdNotifyChainChangedRequestMessage: rpchandlers.HandleNotifyChainChanged,
|
||||
appmessage.CmdGetBlockRequestMessage: rpchandlers.HandleGetBlock,
|
||||
appmessage.CmdGetSubnetworkRequestMessage: rpchandlers.HandleGetSubnetwork,
|
||||
appmessage.CmdGetChainFromBlockRequestMessage: rpchandlers.HandleGetChainFromBlock,
|
||||
appmessage.CmdGetBlocksRequestMessage: rpchandlers.HandleGetBlocks,
|
||||
appmessage.CmdGetBlockCountRequestMessage: rpchandlers.HandleGetBlockCount,
|
||||
appmessage.CmdGetBlockDAGInfoRequestMessage: rpchandlers.HandleGetBlockDAGInfo,
|
||||
appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders,
|
||||
}
|
||||
|
||||
func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) {
|
||||
messageTypes := make([]appmessage.MessageCommand, 0, len(handlers))
|
||||
for messageType := range handlers {
|
||||
messageTypes = append(messageTypes, messageType)
|
||||
}
|
||||
incomingRoute, err := router.AddIncomingRoute(messageTypes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.context.NotificationManager.AddListener(router)
|
||||
|
||||
spawn("routerInitializer-handleIncomingMessages", func() {
|
||||
defer m.context.NotificationManager.RemoveListener(router)
|
||||
|
||||
err := m.handleIncomingMessages(router, incomingRoute)
|
||||
m.handleError(err, netConnection)
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Manager) handleIncomingMessages(router *router.Router, incomingRoute *router.Route) error {
|
||||
outgoingRoute := router.OutgoingRoute()
|
||||
for {
|
||||
request, err := incomingRoute.Dequeue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
handler, ok := handlers[request.Command()]
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
response, err := handler(m.context, router, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = outgoingRoute.Enqueue(response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection) {
|
||||
if errors.Is(err, router.ErrTimeout) {
|
||||
log.Warnf("Got timeout from %s. Disconnecting...", netConnection)
|
||||
netConnection.Disconnect()
|
||||
return
|
||||
}
|
||||
if errors.Is(err, router.ErrRouteClosed) {
|
||||
return
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/mining"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/kaspanet/kaspad/util/random"
|
||||
"github.com/pkg/errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// blockTemplateNonceRange is two 64-bit big-endian hexadecimal integers which
|
||||
// represent the valid ranges of nonces returned by the getBlockTemplate
|
||||
// RPC.
|
||||
blockTemplateNonceRange = "000000000000ffffffffffff"
|
||||
|
||||
// blockTemplateRegenerateSeconds is the number of seconds that must pass before
|
||||
// a new template is generated when the parent block hashes has not
|
||||
// changed and there have been changes to the available transactions
|
||||
// in the memory pool.
|
||||
blockTemplateRegenerateSeconds = 60
|
||||
)
|
||||
|
||||
var (
|
||||
// blockTemplateMutableFields are the manipulations the server allows to be made
|
||||
// to block templates generated by the getBlockTemplate RPC. It is
|
||||
// declared here to avoid the overhead of creating the slice on every
|
||||
// invocation for constant data.
|
||||
blockTemplateMutableFields = []string{
|
||||
"time", "transactions/add", "parentblock", "coinbase/append",
|
||||
}
|
||||
)
|
||||
|
||||
// BlockTemplateState houses state that is used in between multiple RPC invocations to
|
||||
// getBlockTemplate.
|
||||
type BlockTemplateState struct {
|
||||
sync.Mutex
|
||||
|
||||
context *Context
|
||||
|
||||
lastTxUpdate mstime.Time
|
||||
lastGenerated mstime.Time
|
||||
tipHashes []*daghash.Hash
|
||||
minTimestamp mstime.Time
|
||||
template *mining.BlockTemplate
|
||||
notifyMap map[string]map[int64]chan struct{}
|
||||
payAddress util.Address
|
||||
}
|
||||
|
||||
// NewBlockTemplateState returns a new instance of a BlockTemplateState with all internal
|
||||
// fields initialized and ready to use.
|
||||
func NewBlockTemplateState(context *Context) *BlockTemplateState {
|
||||
return &BlockTemplateState{
|
||||
context: context,
|
||||
notifyMap: make(map[string]map[int64]chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the block template state
|
||||
func (bt *BlockTemplateState) Update(payAddress util.Address) error {
|
||||
generator := bt.context.BlockTemplateGenerator
|
||||
lastTxUpdate := generator.TxSource().LastUpdated()
|
||||
if lastTxUpdate.IsZero() {
|
||||
lastTxUpdate = mstime.Now()
|
||||
}
|
||||
|
||||
// Generate a new block template when the current best block has
|
||||
// changed or the transactions in the memory pool have been updated and
|
||||
// it has been at least gbtRegenerateSecond since the last template was
|
||||
// generated.
|
||||
var msgBlock *appmessage.MsgBlock
|
||||
var targetDifficulty string
|
||||
tipHashes := bt.context.DAG.TipHashes()
|
||||
template := bt.template
|
||||
if template == nil || bt.tipHashes == nil ||
|
||||
!daghash.AreEqual(bt.tipHashes, tipHashes) ||
|
||||
bt.payAddress.String() != payAddress.String() ||
|
||||
(bt.lastTxUpdate != lastTxUpdate &&
|
||||
mstime.Now().After(bt.lastGenerated.Add(time.Second*
|
||||
blockTemplateRegenerateSeconds))) {
|
||||
|
||||
// Reset the previous best hash the block template was generated
|
||||
// against so any errors below cause the next invocation to try
|
||||
// again.
|
||||
bt.tipHashes = nil
|
||||
|
||||
// Create a new block template that has a coinbase which anyone
|
||||
// can redeem. This is only acceptable because the returned
|
||||
// block template doesn't include the coinbase, so the caller
|
||||
// will ultimately create their own coinbase which pays to the
|
||||
// appropriate address(es).
|
||||
|
||||
extraNonce, err := random.Uint64()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to randomize extra nonce")
|
||||
}
|
||||
|
||||
blockTemplate, err := generator.NewBlockTemplate(payAddress, extraNonce)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create new block template")
|
||||
}
|
||||
template = blockTemplate
|
||||
msgBlock = template.Block
|
||||
targetDifficulty = fmt.Sprintf("%064x", util.CompactToBig(msgBlock.Header.Bits))
|
||||
|
||||
// Get the minimum allowed timestamp for the block based on the
|
||||
// median timestamp of the last several blocks per the DAG
|
||||
// consensus rules.
|
||||
minTimestamp := bt.context.DAG.NextBlockMinimumTime()
|
||||
|
||||
// Update work state to ensure another block template isn't
|
||||
// generated until needed.
|
||||
bt.template = template
|
||||
bt.lastGenerated = mstime.Now()
|
||||
bt.lastTxUpdate = lastTxUpdate
|
||||
bt.tipHashes = tipHashes
|
||||
bt.minTimestamp = minTimestamp
|
||||
bt.payAddress = payAddress
|
||||
|
||||
log.Debugf("Generated block template (timestamp %s, "+
|
||||
"target %s, merkle root %s)",
|
||||
msgBlock.Header.Timestamp, targetDifficulty,
|
||||
msgBlock.Header.HashMerkleRoot)
|
||||
|
||||
// Notify any clients that are long polling about the new
|
||||
// template.
|
||||
bt.notifyLongPollers(tipHashes, lastTxUpdate)
|
||||
} else {
|
||||
// At this point, there is a saved block template and another
|
||||
// request for a template was made, but either the available
|
||||
// transactions haven't change or it hasn't been long enough to
|
||||
// trigger a new block template to be generated. So, update the
|
||||
// existing block template.
|
||||
|
||||
// Set locals for convenience.
|
||||
msgBlock = template.Block
|
||||
targetDifficulty = fmt.Sprintf("%064x",
|
||||
util.CompactToBig(msgBlock.Header.Bits))
|
||||
|
||||
// Update the time of the block template to the current time
|
||||
// while accounting for the median time of the past several
|
||||
// blocks per the DAG consensus rules.
|
||||
err := generator.UpdateBlockTime(msgBlock)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to update block time")
|
||||
}
|
||||
msgBlock.Header.Nonce = 0
|
||||
|
||||
log.Debugf("Updated block template (timestamp %s, "+
|
||||
"target %s)", msgBlock.Header.Timestamp,
|
||||
targetDifficulty)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Response builds a GetBlockTemplateResponseMessage from the current state
|
||||
func (bt *BlockTemplateState) Response() (*appmessage.GetBlockTemplateResponseMessage, error) {
|
||||
dag := bt.context.DAG
|
||||
// Ensure the timestamps are still in valid range for the template.
|
||||
// This should really only ever happen if the local clock is changed
|
||||
// after the template is generated, but it's important to avoid serving
|
||||
// block templates that will be delayed on other nodes.
|
||||
template := bt.template
|
||||
msgBlock := template.Block
|
||||
header := &msgBlock.Header
|
||||
adjustedTime := dag.Now()
|
||||
maxTime := adjustedTime.Add(time.Millisecond * time.Duration(dag.TimestampDeviationTolerance))
|
||||
if header.Timestamp.After(maxTime) {
|
||||
errorMessage := &appmessage.GetBlockTemplateResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("The template time is after the "+
|
||||
"maximum allowed time for a block - template "+
|
||||
"time %s, maximum time %s", adjustedTime,
|
||||
maxTime)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
// Convert each transaction in the block template to a template result
|
||||
// transaction. The result does not include the coinbase, so notice
|
||||
// the adjustments to the various lengths and indices.
|
||||
numTx := len(msgBlock.Transactions)
|
||||
transactions := make([]appmessage.GetBlockTemplateTransactionMessage, 0, numTx-1)
|
||||
txIndex := make(map[daghash.TxID]int64, numTx)
|
||||
for i, tx := range msgBlock.Transactions {
|
||||
txID := tx.TxID()
|
||||
txIndex[*txID] = int64(i)
|
||||
|
||||
// Create an array of 1-based indices to transactions that come
|
||||
// before this one in the transactions list which this one
|
||||
// depends on. This is necessary since the created block must
|
||||
// ensure proper ordering of the dependencies. A map is used
|
||||
// before creating the final array to prevent duplicate entries
|
||||
// when multiple inputs reference the same transaction.
|
||||
dependsMap := make(map[int64]struct{})
|
||||
for _, txIn := range tx.TxIn {
|
||||
if idx, ok := txIndex[txIn.PreviousOutpoint.TxID]; ok {
|
||||
dependsMap[idx] = struct{}{}
|
||||
}
|
||||
}
|
||||
depends := make([]int64, 0, len(dependsMap))
|
||||
for idx := range dependsMap {
|
||||
depends = append(depends, idx)
|
||||
}
|
||||
|
||||
// Serialize the transaction for later conversion to hex.
|
||||
txBuf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
|
||||
if err := tx.Serialize(txBuf); err != nil {
|
||||
errorMessage := &appmessage.GetBlockTemplateResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Failed to serialize transaction: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
resultTx := appmessage.GetBlockTemplateTransactionMessage{
|
||||
Data: hex.EncodeToString(txBuf.Bytes()),
|
||||
ID: txID.String(),
|
||||
Depends: depends,
|
||||
Mass: template.TxMasses[i],
|
||||
Fee: template.Fees[i],
|
||||
}
|
||||
transactions = append(transactions, resultTx)
|
||||
}
|
||||
|
||||
// Generate the block template reply. Note that following mutations are
|
||||
// implied by the included or omission of fields:
|
||||
// Including MinTime -> time/decrement
|
||||
// Omitting CoinbaseTxn -> coinbase, generation
|
||||
targetDifficulty := fmt.Sprintf("%064x", util.CompactToBig(header.Bits))
|
||||
longPollID := bt.encodeLongPollID(bt.tipHashes, bt.payAddress, bt.lastGenerated)
|
||||
|
||||
// Check whether this node is synced with the rest of of the
|
||||
// network. There's almost never a good reason to mine on top
|
||||
// of an unsynced DAG, and miners are generally expected not to
|
||||
// mine when isSynced is false.
|
||||
// This is not a straight-up error because the choice of whether
|
||||
// to mine or not is the responsibility of the miner rather
|
||||
// than the node's.
|
||||
isSynced := bt.context.BlockTemplateGenerator.IsSynced()
|
||||
isConnected := len(bt.context.ProtocolManager.Peers()) > 0
|
||||
|
||||
reply := appmessage.GetBlockTemplateResponseMessage{
|
||||
Bits: strconv.FormatInt(int64(header.Bits), 16),
|
||||
CurrentTime: header.Timestamp.UnixMilliseconds(),
|
||||
ParentHashes: daghash.Strings(header.ParentHashes),
|
||||
MassLimit: appmessage.MaxMassPerBlock,
|
||||
Transactions: transactions,
|
||||
HashMerkleRoot: header.HashMerkleRoot.String(),
|
||||
AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot.String(),
|
||||
UTXOCommitment: header.UTXOCommitment.String(),
|
||||
Version: header.Version,
|
||||
LongPollID: longPollID,
|
||||
TargetDifficulty: targetDifficulty,
|
||||
MinTime: bt.minTimestamp.UnixMilliseconds(),
|
||||
MaxTime: maxTime.UnixMilliseconds(),
|
||||
MutableFields: blockTemplateMutableFields,
|
||||
NonceRange: blockTemplateNonceRange,
|
||||
IsSynced: isSynced,
|
||||
IsConnected: isConnected,
|
||||
}
|
||||
|
||||
return &reply, nil
|
||||
}
|
||||
|
||||
// notifyLongPollers notifies any channels that have been registered to be
|
||||
// notified when block templates are stale.
|
||||
//
|
||||
// This function MUST be called with the state locked.
|
||||
func (bt *BlockTemplateState) notifyLongPollers(tipHashes []*daghash.Hash, lastGenerated mstime.Time) {
|
||||
// Notify anything that is waiting for a block template update from
|
||||
// hashes which are not the current tip hashes.
|
||||
tipHashesStr := daghash.JoinHashesStrings(tipHashes, "")
|
||||
for hashesStr, channels := range bt.notifyMap {
|
||||
if hashesStr != tipHashesStr {
|
||||
for _, c := range channels {
|
||||
close(c)
|
||||
}
|
||||
delete(bt.notifyMap, hashesStr)
|
||||
}
|
||||
}
|
||||
|
||||
// Return now if the provided last generated timestamp has not been
|
||||
// initialized.
|
||||
if lastGenerated.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
// Return now if there is nothing registered for updates to the current
|
||||
// best block hash.
|
||||
channels, ok := bt.notifyMap[tipHashesStr]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Notify anything that is waiting for a block template update from a
|
||||
// block template generated before the most recently generated block
|
||||
// template.
|
||||
lastGeneratedUnix := lastGenerated.UnixSeconds()
|
||||
for lastGen, c := range channels {
|
||||
if lastGen < lastGeneratedUnix {
|
||||
close(c)
|
||||
delete(channels, lastGen)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the entry altogether if there are no more registered
|
||||
// channels.
|
||||
if len(channels) == 0 {
|
||||
delete(bt.notifyMap, tipHashesStr)
|
||||
}
|
||||
}
|
||||
|
||||
// NotifyBlockAdded uses the newly-added block to notify any long poll
|
||||
// clients with a new block template when their existing block template is
|
||||
// stale due to the newly added block.
|
||||
func (bt *BlockTemplateState) NotifyBlockAdded(block *util.Block) {
|
||||
spawn("BlockTemplateState.NotifyBlockAdded", func() {
|
||||
bt.Lock()
|
||||
defer bt.Unlock()
|
||||
|
||||
bt.notifyLongPollers(block.MsgBlock().Header.ParentHashes, bt.lastTxUpdate)
|
||||
})
|
||||
}
|
||||
|
||||
// NotifyMempoolTx uses the new last updated time for the transaction memory
|
||||
// pool to notify any long poll clients with a new block template when their
|
||||
// existing block template is stale due to enough time passing and the contents
|
||||
// of the memory pool changing.
|
||||
func (bt *BlockTemplateState) NotifyMempoolTx() {
|
||||
lastUpdated := bt.context.Mempool.LastUpdated()
|
||||
spawn("BlockTemplateState", func() {
|
||||
bt.Lock()
|
||||
defer bt.Unlock()
|
||||
|
||||
// No need to notify anything if no block templates have been generated
|
||||
// yet.
|
||||
if bt.tipHashes == nil || bt.lastGenerated.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
if mstime.Now().After(bt.lastGenerated.Add(time.Second *
|
||||
blockTemplateRegenerateSeconds)) {
|
||||
|
||||
bt.notifyLongPollers(bt.tipHashes, lastUpdated)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BlockTemplateOrLongPollChan returns a block template if the
|
||||
// template identified by the provided long poll ID is stale or
|
||||
// invalid. Otherwise, it returns a channel that will notify
|
||||
// when there's a more current template.
|
||||
func (bt *BlockTemplateState) BlockTemplateOrLongPollChan(longPollID string,
|
||||
payAddress util.Address) (*appmessage.GetBlockTemplateResponseMessage, chan struct{}, error) {
|
||||
|
||||
bt.Lock()
|
||||
defer bt.Unlock()
|
||||
|
||||
if err := bt.Update(payAddress); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Just return the current block template if the long poll ID provided by
|
||||
// the caller is invalid.
|
||||
parentHashes, lastGenerated, err := bt.decodeLongPollID(longPollID)
|
||||
if err != nil {
|
||||
result, err := bt.Response()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return result, nil, nil
|
||||
}
|
||||
|
||||
// Return the block template now if the specific block template
|
||||
// identified by the long poll ID no longer matches the current block
|
||||
// template as this means the provided template is stale.
|
||||
areHashesEqual := daghash.AreEqual(bt.template.Block.Header.ParentHashes, parentHashes)
|
||||
if !areHashesEqual ||
|
||||
lastGenerated != bt.lastGenerated.UnixSeconds() {
|
||||
|
||||
// Include whether or not it is valid to submit work against the
|
||||
// old block template depending on whether or not a solution has
|
||||
// already been found and added to the block DAG.
|
||||
result, err := bt.Response()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return result, nil, nil
|
||||
}
|
||||
|
||||
// Register the parent hashes and last generated time for notifications
|
||||
// Get a channel that will be notified when the template associated with
|
||||
// the provided ID is stale and a new block template should be returned to
|
||||
// the caller.
|
||||
longPollChan := bt.templateUpdateChan(parentHashes, lastGenerated)
|
||||
return nil, longPollChan, nil
|
||||
}
|
||||
|
||||
// templateUpdateChan returns a channel that will be closed once the block
|
||||
// template associated with the passed parent hashes and last generated time
|
||||
// is stale. The function will return existing channels for duplicate
|
||||
// parameters which allows multiple clients to wait for the same block template
|
||||
// without requiring a different channel for each client.
|
||||
//
|
||||
// This function MUST be called with the state locked.
|
||||
func (bt *BlockTemplateState) templateUpdateChan(tipHashes []*daghash.Hash, lastGenerated int64) chan struct{} {
|
||||
tipHashesStr := daghash.JoinHashesStrings(tipHashes, "")
|
||||
// Either get the current list of channels waiting for updates about
|
||||
// changes to block template for the parent hashes or create a new one.
|
||||
channels, ok := bt.notifyMap[tipHashesStr]
|
||||
if !ok {
|
||||
m := make(map[int64]chan struct{})
|
||||
bt.notifyMap[tipHashesStr] = m
|
||||
channels = m
|
||||
}
|
||||
|
||||
// Get the current channel associated with the time the block template
|
||||
// was last generated or create a new one.
|
||||
c, ok := channels[lastGenerated]
|
||||
if !ok {
|
||||
c = make(chan struct{})
|
||||
channels[lastGenerated] = c
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// encodeLongPollID encodes the passed details into an ID that can be used to
|
||||
// uniquely identify a block template.
|
||||
func (bt *BlockTemplateState) encodeLongPollID(parentHashes []*daghash.Hash, miningAddress util.Address, lastGenerated mstime.Time) string {
|
||||
return fmt.Sprintf("%s-%s-%d", daghash.JoinHashesStrings(parentHashes, ""), miningAddress, lastGenerated.UnixSeconds())
|
||||
}
|
||||
|
||||
// decodeLongPollID decodes an ID that is used to uniquely identify a block
|
||||
// template. This is mainly used as a mechanism to track when to update clients
|
||||
// that are using long polling for block templates. The ID consists of the
|
||||
// parent blocks hashes for the associated template and the time the associated
|
||||
// template was generated.
|
||||
func (bt *BlockTemplateState) decodeLongPollID(longPollID string) ([]*daghash.Hash, int64, error) {
|
||||
fields := strings.Split(longPollID, "-")
|
||||
if len(fields) != 2 {
|
||||
return nil, 0, errors.New("decodeLongPollID: invalid number of fields")
|
||||
}
|
||||
|
||||
parentHashesStr := fields[0]
|
||||
if len(parentHashesStr)%daghash.HashSize != 0 {
|
||||
return nil, 0, errors.New("decodeLongPollID: invalid parent hashes format")
|
||||
}
|
||||
numberOfHashes := len(parentHashesStr) / daghash.HashSize
|
||||
|
||||
parentHashes := make([]*daghash.Hash, 0, numberOfHashes)
|
||||
|
||||
for i := 0; i < len(parentHashesStr); i += daghash.HashSize {
|
||||
hash, err := daghash.NewHashFromStr(parentHashesStr[i : i+daghash.HashSize])
|
||||
if err != nil {
|
||||
return nil, 0, errors.Errorf("decodeLongPollID: NewHashFromStr: %s", err)
|
||||
}
|
||||
parentHashes = append(parentHashes, hash)
|
||||
}
|
||||
|
||||
lastGenerated, err := strconv.ParseInt(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Errorf("decodeLongPollID: Cannot parse timestamp %s: %s", fields[1], err)
|
||||
}
|
||||
|
||||
return parentHashes, lastGenerated, nil
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// CollectChainBlocks creates a slice of chain blocks from the given hashes
|
||||
func (ctx *Context) CollectChainBlocks(hashes []*daghash.Hash) ([]*appmessage.ChainBlock, error) {
|
||||
chainBlocks := make([]*appmessage.ChainBlock, 0, len(hashes))
|
||||
for _, hash := range hashes {
|
||||
acceptanceData, err := ctx.AcceptanceIndex.TxsAcceptanceData(hash)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("could not retrieve acceptance data for block %s", hash)
|
||||
}
|
||||
|
||||
acceptedBlocks := make([]*appmessage.AcceptedBlock, 0, len(acceptanceData))
|
||||
for _, blockAcceptanceData := range acceptanceData {
|
||||
acceptedTxIds := make([]string, 0, len(blockAcceptanceData.TxAcceptanceData))
|
||||
for _, txAcceptanceData := range blockAcceptanceData.TxAcceptanceData {
|
||||
if txAcceptanceData.IsAccepted {
|
||||
acceptedTxIds = append(acceptedTxIds, txAcceptanceData.Tx.ID().String())
|
||||
}
|
||||
}
|
||||
acceptedBlock := &appmessage.AcceptedBlock{
|
||||
Hash: blockAcceptanceData.BlockHash.String(),
|
||||
AcceptedTxIDs: acceptedTxIds,
|
||||
}
|
||||
acceptedBlocks = append(acceptedBlocks, acceptedBlock)
|
||||
}
|
||||
|
||||
chainBlock := &appmessage.ChainBlock{
|
||||
Hash: hash.String(),
|
||||
AcceptedBlocks: acceptedBlocks,
|
||||
}
|
||||
chainBlocks = append(chainBlocks, chainBlock)
|
||||
}
|
||||
return chainBlocks, nil
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag/indexers"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/domain/mining"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
)
|
||||
|
||||
// Context represents the RPC context
|
||||
type Context struct {
|
||||
Config *config.Config
|
||||
NetAdapter *netadapter.NetAdapter
|
||||
DAG *blockdag.BlockDAG
|
||||
ProtocolManager *protocol.Manager
|
||||
ConnectionManager *connmanager.ConnectionManager
|
||||
BlockTemplateGenerator *mining.BlkTmplGenerator
|
||||
Mempool *mempool.TxPool
|
||||
AddressManager *addressmanager.AddressManager
|
||||
AcceptanceIndex *indexers.AcceptanceIndex
|
||||
|
||||
BlockTemplateState *BlockTemplateState
|
||||
NotificationManager *NotificationManager
|
||||
}
|
||||
|
||||
// NewContext creates a new RPC context
|
||||
func NewContext(
|
||||
cfg *config.Config,
|
||||
netAdapter *netadapter.NetAdapter,
|
||||
dag *blockdag.BlockDAG,
|
||||
protocolManager *protocol.Manager,
|
||||
connectionManager *connmanager.ConnectionManager,
|
||||
blockTemplateGenerator *mining.BlkTmplGenerator,
|
||||
mempool *mempool.TxPool,
|
||||
addressManager *addressmanager.AddressManager,
|
||||
acceptanceIndex *indexers.AcceptanceIndex) *Context {
|
||||
context := &Context{
|
||||
Config: cfg,
|
||||
NetAdapter: netAdapter,
|
||||
DAG: dag,
|
||||
ProtocolManager: protocolManager,
|
||||
ConnectionManager: connectionManager,
|
||||
BlockTemplateGenerator: blockTemplateGenerator,
|
||||
Mempool: mempool,
|
||||
AddressManager: addressManager,
|
||||
AcceptanceIndex: acceptanceIndex,
|
||||
}
|
||||
context.BlockTemplateState = NewBlockTemplateState(context)
|
||||
context.NotificationManager = NewNotificationManager()
|
||||
return context
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.RPCS)
|
||||
var spawn = panics.GoroutineWrapperFunc(log)
|
||||
@@ -1,107 +0,0 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// NotificationManager manages notifications for the RPC
|
||||
type NotificationManager struct {
|
||||
sync.RWMutex
|
||||
listeners map[*routerpkg.Router]*NotificationListener
|
||||
}
|
||||
|
||||
// NotificationListener represents a registered RPC notification listener
|
||||
type NotificationListener struct {
|
||||
propagateBlockAddedNotifications bool
|
||||
propagateChainChangedNotifications bool
|
||||
}
|
||||
|
||||
// NewNotificationManager creates a new NotificationManager
|
||||
func NewNotificationManager() *NotificationManager {
|
||||
return &NotificationManager{
|
||||
listeners: make(map[*routerpkg.Router]*NotificationListener),
|
||||
}
|
||||
}
|
||||
|
||||
// AddListener registers a listener with the given router
|
||||
func (nm *NotificationManager) AddListener(router *routerpkg.Router) {
|
||||
nm.Lock()
|
||||
defer nm.Unlock()
|
||||
|
||||
listener := newNotificationListener()
|
||||
nm.listeners[router] = listener
|
||||
}
|
||||
|
||||
// RemoveListener unregisters the given router
|
||||
func (nm *NotificationManager) RemoveListener(router *routerpkg.Router) {
|
||||
nm.Lock()
|
||||
defer nm.Unlock()
|
||||
|
||||
delete(nm.listeners, router)
|
||||
}
|
||||
|
||||
// Listener retrieves the listener registered with the given router
|
||||
func (nm *NotificationManager) Listener(router *routerpkg.Router) (*NotificationListener, error) {
|
||||
nm.RLock()
|
||||
defer nm.RUnlock()
|
||||
|
||||
listener, ok := nm.listeners[router]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("listener not found")
|
||||
}
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
// NotifyBlockAdded notifies the notification manager that a block has been added to the DAG
|
||||
func (nm *NotificationManager) NotifyBlockAdded(notification *appmessage.BlockAddedNotificationMessage) error {
|
||||
nm.RLock()
|
||||
defer nm.RUnlock()
|
||||
|
||||
for router, listener := range nm.listeners {
|
||||
if listener.propagateBlockAddedNotifications {
|
||||
err := router.OutgoingRoute().Enqueue(notification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyChainChanged notifies the notification manager that the DAG's selected parent chain has changed
|
||||
func (nm *NotificationManager) NotifyChainChanged(notification *appmessage.ChainChangedNotificationMessage) error {
|
||||
nm.RLock()
|
||||
defer nm.RUnlock()
|
||||
|
||||
for router, listener := range nm.listeners {
|
||||
if listener.propagateChainChangedNotifications {
|
||||
err := router.OutgoingRoute().Enqueue(notification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newNotificationListener() *NotificationListener {
|
||||
return &NotificationListener{
|
||||
propagateBlockAddedNotifications: false,
|
||||
propagateChainChangedNotifications: false,
|
||||
}
|
||||
}
|
||||
|
||||
// PropagateBlockAddedNotifications instructs the listener to send block added notifications
|
||||
// to the remote listener
|
||||
func (nl *NotificationListener) PropagateBlockAddedNotifications() {
|
||||
nl.propagateBlockAddedNotifications = true
|
||||
}
|
||||
|
||||
// PropagateChainChangedNotifications instructs the listener to send chain changed notifications
|
||||
// to the remote listener
|
||||
func (nl *NotificationListener) PropagateChainChangedNotifications() {
|
||||
nl.propagateChainChangedNotifications = true
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
package rpccontext
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domain/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/pointers"
|
||||
"math/big"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// BuildBlockVerboseData builds a BlockVerboseData from the given block.
|
||||
// This method must be called with the DAG lock held for reads
|
||||
func (ctx *Context) BuildBlockVerboseData(block *util.Block, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) {
|
||||
hash := block.Hash()
|
||||
params := ctx.DAG.Params
|
||||
blockHeader := block.MsgBlock().Header
|
||||
|
||||
blockBlueScore, err := ctx.DAG.BlueScoreByBlockHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the hashes for the next blocks unless there are none.
|
||||
childHashes, err := ctx.DAG.ChildHashesByHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockConfirmations, err := ctx.DAG.BlockConfirmationsByHashNoLock(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
selectedParentHash, err := ctx.DAG.SelectedParentHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selectedParentHashStr := ""
|
||||
if selectedParentHash != nil {
|
||||
selectedParentHashStr = selectedParentHash.String()
|
||||
}
|
||||
|
||||
isChainBlock, err := ctx.DAG.IsInSelectedParentChain(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acceptedBlockHashes, err := ctx.DAG.BluesByBlockHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &appmessage.BlockVerboseData{
|
||||
Hash: hash.String(),
|
||||
Version: blockHeader.Version,
|
||||
VersionHex: fmt.Sprintf("%08x", blockHeader.Version),
|
||||
HashMerkleRoot: blockHeader.HashMerkleRoot.String(),
|
||||
AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot.String(),
|
||||
UTXOCommitment: blockHeader.UTXOCommitment.String(),
|
||||
ParentHashes: daghash.Strings(blockHeader.ParentHashes),
|
||||
SelectedParentHash: selectedParentHashStr,
|
||||
Nonce: blockHeader.Nonce,
|
||||
Time: blockHeader.Timestamp.UnixMilliseconds(),
|
||||
Confirmations: blockConfirmations,
|
||||
BlueScore: blockBlueScore,
|
||||
IsChainBlock: isChainBlock,
|
||||
Size: int32(block.MsgBlock().SerializeSize()),
|
||||
Bits: strconv.FormatInt(int64(blockHeader.Bits), 16),
|
||||
Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits, params),
|
||||
ChildHashes: daghash.Strings(childHashes),
|
||||
AcceptedBlockHashes: daghash.Strings(acceptedBlockHashes),
|
||||
}
|
||||
|
||||
transactions := block.Transactions()
|
||||
txIDs := make([]string, len(transactions))
|
||||
for i, tx := range transactions {
|
||||
txIDs[i] = tx.ID().String()
|
||||
}
|
||||
result.TxIDs = txIDs
|
||||
|
||||
if includeTransactionVerboseData {
|
||||
transactions := block.Transactions()
|
||||
transactionVerboseData := make([]*appmessage.TransactionVerboseData, len(transactions))
|
||||
for i, tx := range transactions {
|
||||
data, err := ctx.buildTransactionVerboseData(tx.MsgTx(), tx.ID().String(),
|
||||
&blockHeader, hash.String(), nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transactionVerboseData[i] = data
|
||||
}
|
||||
result.TransactionVerboseData = transactionVerboseData
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetDifficultyRatio returns the proof-of-work difficulty as a multiple of the
|
||||
// minimum difficulty using the passed bits field from the header of a block.
|
||||
func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) float64 {
|
||||
// The minimum difficulty is the max possible proof-of-work limit bits
|
||||
// converted back to a number. Note this is not the same as the proof of
|
||||
// work limit directly because the block difficulty is encoded in a block
|
||||
// with the compact form which loses precision.
|
||||
target := util.CompactToBig(bits)
|
||||
|
||||
difficulty := new(big.Rat).SetFrac(params.PowMax, target)
|
||||
outString := difficulty.FloatString(8)
|
||||
diff, err := strconv.ParseFloat(outString, 64)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot get difficulty: %s", err)
|
||||
return 0
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
func (ctx *Context) buildTransactionVerboseData(mtx *appmessage.MsgTx,
|
||||
txID string, blockHeader *appmessage.BlockHeader, blockHash string,
|
||||
acceptingBlock *daghash.Hash, isInMempool bool) (*appmessage.TransactionVerboseData, error) {
|
||||
|
||||
mtxHex, err := msgTxToHex(mtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var payloadHash string
|
||||
if mtx.PayloadHash != nil {
|
||||
payloadHash = mtx.PayloadHash.String()
|
||||
}
|
||||
|
||||
txReply := &appmessage.TransactionVerboseData{
|
||||
Hex: mtxHex,
|
||||
TxID: txID,
|
||||
Hash: mtx.TxHash().String(),
|
||||
Size: int32(mtx.SerializeSize()),
|
||||
TransactionVerboseInputs: ctx.buildTransactionVerboseInputs(mtx),
|
||||
TransactionVerboseOutputs: ctx.buildTransactionVerboseOutputs(mtx, nil),
|
||||
Version: mtx.Version,
|
||||
LockTime: mtx.LockTime,
|
||||
SubnetworkID: mtx.SubnetworkID.String(),
|
||||
Gas: mtx.Gas,
|
||||
PayloadHash: payloadHash,
|
||||
Payload: hex.EncodeToString(mtx.Payload),
|
||||
}
|
||||
|
||||
if blockHeader != nil {
|
||||
txReply.Time = uint64(blockHeader.Timestamp.UnixMilliseconds())
|
||||
txReply.BlockTime = uint64(blockHeader.Timestamp.UnixMilliseconds())
|
||||
txReply.BlockHash = blockHash
|
||||
}
|
||||
|
||||
txReply.IsInMempool = isInMempool
|
||||
if acceptingBlock != nil {
|
||||
txReply.AcceptedBy = acceptingBlock.String()
|
||||
}
|
||||
|
||||
return txReply, nil
|
||||
}
|
||||
|
||||
// msgTxToHex serializes a transaction using the latest protocol version and
|
||||
// returns a hex-encoded string of the result.
|
||||
func msgTxToHex(msgTx *appmessage.MsgTx) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
err := msgTx.KaspaEncode(&buf, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hex.EncodeToString(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
func (ctx *Context) buildTransactionVerboseInputs(mtx *appmessage.MsgTx) []*appmessage.TransactionVerboseInput {
|
||||
inputs := make([]*appmessage.TransactionVerboseInput, len(mtx.TxIn))
|
||||
for i, txIn := range mtx.TxIn {
|
||||
// The disassembled string will contain [error] inline
|
||||
// if the script doesn't fully parse, so ignore the
|
||||
// error here.
|
||||
disbuf, _ := txscript.DisasmString(txIn.SignatureScript)
|
||||
|
||||
input := &appmessage.TransactionVerboseInput{}
|
||||
input.TxID = txIn.PreviousOutpoint.TxID.String()
|
||||
input.OutputIndex = txIn.PreviousOutpoint.Index
|
||||
input.Sequence = txIn.Sequence
|
||||
input.ScriptSig = &appmessage.ScriptSig{
|
||||
Asm: disbuf,
|
||||
Hex: hex.EncodeToString(txIn.SignatureScript),
|
||||
}
|
||||
inputs[i] = input
|
||||
}
|
||||
|
||||
return inputs
|
||||
}
|
||||
|
||||
// buildTransactionVerboseOutputs returns a slice of JSON objects for the outputs of the passed
|
||||
// transaction.
|
||||
func (ctx *Context) buildTransactionVerboseOutputs(mtx *appmessage.MsgTx, filterAddrMap map[string]struct{}) []*appmessage.TransactionVerboseOutput {
|
||||
outputs := make([]*appmessage.TransactionVerboseOutput, len(mtx.TxOut))
|
||||
for i, v := range mtx.TxOut {
|
||||
// The disassembled string will contain [error] inline if the
|
||||
// script doesn't fully parse, so ignore the error here.
|
||||
disbuf, _ := txscript.DisasmString(v.ScriptPubKey)
|
||||
|
||||
// Ignore the error here since an error means the script
|
||||
// couldn't parse and there is no additional information about
|
||||
// it anyways.
|
||||
scriptClass, addr, _ := txscript.ExtractScriptPubKeyAddress(
|
||||
v.ScriptPubKey, ctx.DAG.Params)
|
||||
|
||||
// Encode the addresses while checking if the address passes the
|
||||
// filter when needed.
|
||||
passesFilter := len(filterAddrMap) == 0
|
||||
var encodedAddr string
|
||||
if addr != nil {
|
||||
encodedAddr = *pointers.String(addr.EncodeAddress())
|
||||
|
||||
// If the filter doesn't already pass, make it pass if
|
||||
// the address exists in the filter.
|
||||
if _, exists := filterAddrMap[encodedAddr]; exists {
|
||||
passesFilter = true
|
||||
}
|
||||
}
|
||||
|
||||
if !passesFilter {
|
||||
continue
|
||||
}
|
||||
|
||||
output := &appmessage.TransactionVerboseOutput{}
|
||||
output.Index = uint32(i)
|
||||
output.Value = v.Value
|
||||
output.ScriptPubKey = &appmessage.ScriptPubKeyResult{
|
||||
Address: encodedAddr,
|
||||
Asm: disbuf,
|
||||
Hex: hex.EncodeToString(v.ScriptPubKey),
|
||||
Type: scriptClass.String(),
|
||||
}
|
||||
outputs[i] = output
|
||||
}
|
||||
|
||||
return outputs
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/network"
|
||||
)
|
||||
|
||||
// HandleAddPeer handles the respectively named RPC command
|
||||
func HandleAddPeer(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
AddPeerRequest := request.(*appmessage.AddPeerRequestMessage)
|
||||
address, err := network.NormalizeAddress(AddPeerRequest.Address, context.DAG.Params.DefaultPort)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.AddPeerResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse address: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
context.ConnectionManager.AddConnectionRequest(address, AddPeerRequest.IsPermanent)
|
||||
|
||||
response := appmessage.NewAddPeerResponseMessage()
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
)
|
||||
|
||||
// HandleGetBlock handles the respectively named RPC command
|
||||
func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getBlockRequest := request.(*appmessage.GetBlockRequestMessage)
|
||||
|
||||
// Load the raw block bytes from the database.
|
||||
hash, err := daghash.NewHashFromStr(getBlockRequest.Hash)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Hash could not be parsed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
context.DAG.RLock()
|
||||
defer context.DAG.RUnlock()
|
||||
|
||||
if context.DAG.IsKnownInvalid(hash) {
|
||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block %s is known to be invalid", hash)
|
||||
return errorMessage, nil
|
||||
}
|
||||
if context.DAG.IsKnownOrphan(hash) {
|
||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block %s is an orphan", hash)
|
||||
return errorMessage, nil
|
||||
}
|
||||
block, err := context.DAG.BlockByHash(hash)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block %s not found", hash)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
blockBytes, err := block.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Handle partial blocks
|
||||
if getBlockRequest.SubnetworkID != "" {
|
||||
requestSubnetworkID, err := subnetworkid.NewFromStr(getBlockRequest.SubnetworkID)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("SubnetworkID could not be parsed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
nodeSubnetworkID := context.Config.SubnetworkID
|
||||
|
||||
if requestSubnetworkID != nil {
|
||||
if nodeSubnetworkID != nil {
|
||||
if !nodeSubnetworkID.IsEqual(requestSubnetworkID) {
|
||||
errorMessage := &appmessage.GetBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("subnetwork %s does not match this partial node",
|
||||
getBlockRequest.SubnetworkID)
|
||||
return errorMessage, nil
|
||||
}
|
||||
// nothing to do - partial node stores partial blocks
|
||||
} else {
|
||||
// Deserialize the block.
|
||||
msgBlock := block.MsgBlock()
|
||||
msgBlock.ConvertToPartial(requestSubnetworkID)
|
||||
var b bytes.Buffer
|
||||
err := msgBlock.Serialize(bufio.NewWriter(&b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockBytes = b.Bytes()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response := appmessage.NewGetBlockResponseMessage()
|
||||
|
||||
if getBlockRequest.IncludeBlockHex {
|
||||
response.BlockHex = hex.EncodeToString(blockBytes)
|
||||
}
|
||||
if getBlockRequest.IncludeBlockVerboseData {
|
||||
blockVerboseData, err := context.BuildBlockVerboseData(block, getBlockRequest.IncludeTransactionVerboseData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.BlockVerboseData = blockVerboseData
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetBlockCount handles the respectively named RPC command
|
||||
func HandleGetBlockCount(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
response := appmessage.NewGetBlockCountResponseMessage(context.DAG.BlockCount())
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
// HandleGetBlockDAGInfo handles the respectively named RPC command
|
||||
func HandleGetBlockDAGInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
dag := context.DAG
|
||||
params := dag.Params
|
||||
|
||||
response := appmessage.NewGetBlockDAGInfoResponseMessage()
|
||||
response.NetworkName = params.Name
|
||||
response.BlockCount = dag.BlockCount()
|
||||
response.TipHashes = daghash.Strings(dag.TipHashes())
|
||||
response.Difficulty = context.GetDifficultyRatio(dag.CurrentBits(), params)
|
||||
response.PastMedianTime = dag.CalcPastMedianTime().UnixMilliseconds()
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
// HandleGetBlockTemplate handles the respectively named RPC command
|
||||
func HandleGetBlockTemplate(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getBlockTemplateRequest := request.(*appmessage.GetBlockTemplateRequestMessage)
|
||||
|
||||
payAddress, err := util.DecodeAddress(getBlockTemplateRequest.PayAddress, context.DAG.Params.Prefix)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetBlockTemplateResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not decode address: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
// When a long poll ID was provided, this is a long poll request by the
|
||||
// client to be notified when block template referenced by the ID should
|
||||
// be replaced with a new one.
|
||||
if getBlockTemplateRequest.LongPollID != "" {
|
||||
return handleGetBlockTemplateLongPoll(context, getBlockTemplateRequest.LongPollID, payAddress)
|
||||
}
|
||||
|
||||
// Protect concurrent access when updating block templates.
|
||||
context.BlockTemplateState.Lock()
|
||||
defer context.BlockTemplateState.Unlock()
|
||||
|
||||
// Get and return a block template. A new block template will be
|
||||
// generated when the current best block has changed or the transactions
|
||||
// in the memory pool have been updated and it has been at least five
|
||||
// seconds since the last template was generated. Otherwise, the
|
||||
// timestamp for the existing block template is updated (and possibly
|
||||
// the difficulty on testnet per the consesus rules).
|
||||
err = context.BlockTemplateState.Update(payAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return context.BlockTemplateState.Response()
|
||||
}
|
||||
|
||||
// handleGetBlockTemplateLongPoll is a helper for handleGetBlockTemplateRequest
|
||||
// which deals with handling long polling for block templates. When a caller
|
||||
// sends a request with a long poll ID that was previously returned, a response
|
||||
// is not sent until the caller should stop working on the previous block
|
||||
// template in favor of the new one. In particular, this is the case when the
|
||||
// old block template is no longer valid due to a solution already being found
|
||||
// and added to the block DAG, or new transactions have shown up and some time
|
||||
// has passed without finding a solution.
|
||||
func handleGetBlockTemplateLongPoll(context *rpccontext.Context, longPollID string,
|
||||
payAddress util.Address) (*appmessage.GetBlockTemplateResponseMessage, error) {
|
||||
state := context.BlockTemplateState
|
||||
|
||||
result, longPollChan, err := state.BlockTemplateOrLongPollChan(longPollID, payAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Wait until signal received to send the reply.
|
||||
<-longPollChan
|
||||
|
||||
// Get the lastest block template
|
||||
state.Lock()
|
||||
defer state.Unlock()
|
||||
|
||||
if err := state.Update(payAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Include whether or not it is valid to submit work against the old
|
||||
// block template depending on whether or not a solution has already
|
||||
// been found and added to the block DAG.
|
||||
result, err = state.Response()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxBlocksInGetBlocksResponse is the max amount of blocks that are
|
||||
// allowed in a GetBlocksResult.
|
||||
maxBlocksInGetBlocksResponse = 1000
|
||||
)
|
||||
|
||||
// HandleGetBlocks handles the respectively named RPC command
|
||||
func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getBlocksRequest := request.(*appmessage.GetBlocksRequestMessage)
|
||||
|
||||
var lowHash *daghash.Hash
|
||||
if getBlocksRequest.LowHash != "" {
|
||||
lowHash = &daghash.Hash{}
|
||||
err := daghash.Decode(lowHash, getBlocksRequest.LowHash)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetBlocksResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse lowHash: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
}
|
||||
|
||||
context.DAG.RLock()
|
||||
defer context.DAG.RUnlock()
|
||||
|
||||
// If lowHash is not in the DAG, there's nothing to do; return an error.
|
||||
if lowHash != nil && !context.DAG.IsKnownBlock(lowHash) {
|
||||
errorMessage := &appmessage.GetBlocksResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block %s not found in DAG", lowHash)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
// Retrieve the block hashes.
|
||||
blockHashes, err := context.DAG.BlockHashesFrom(lowHash, maxBlocksInGetBlocksResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert the hashes to strings
|
||||
hashes := make([]string, len(blockHashes))
|
||||
for i, blockHash := range blockHashes {
|
||||
hashes[i] = blockHash.String()
|
||||
}
|
||||
|
||||
// Include more data if requested
|
||||
var blockHexes []string
|
||||
var blockVerboseData []*appmessage.BlockVerboseData
|
||||
if getBlocksRequest.IncludeBlockHexes || getBlocksRequest.IncludeBlockVerboseData {
|
||||
blockBytesSlice, err := hashesToBlockBytes(context, blockHashes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if getBlocksRequest.IncludeBlockHexes {
|
||||
blockHexes = blockBytesToStrings(blockBytesSlice)
|
||||
}
|
||||
if getBlocksRequest.IncludeBlockVerboseData {
|
||||
data, err := blockBytesToBlockVerboseResults(context, blockBytesSlice, getBlocksRequest.IncludeBlockVerboseData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockVerboseData = data
|
||||
}
|
||||
}
|
||||
|
||||
response := appmessage.NewGetBlocksResponseMessage(hashes, blockHexes, blockVerboseData)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func hashesToBlockBytes(context *rpccontext.Context, hashes []*daghash.Hash) ([][]byte, error) {
|
||||
blocks := make([][]byte, len(hashes))
|
||||
for i, hash := range hashes {
|
||||
block, err := context.DAG.BlockByHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockBytes, err := block.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocks[i] = blockBytes
|
||||
}
|
||||
return blocks, nil
|
||||
}
|
||||
func blockBytesToStrings(blockBytesSlice [][]byte) []string {
|
||||
rawBlocks := make([]string, len(blockBytesSlice))
|
||||
for i, blockBytes := range blockBytesSlice {
|
||||
rawBlocks[i] = hex.EncodeToString(blockBytes)
|
||||
}
|
||||
return rawBlocks
|
||||
}
|
||||
|
||||
func blockBytesToBlockVerboseResults(context *rpccontext.Context, blockBytesSlice [][]byte,
|
||||
includeTransactionVerboseData bool) ([]*appmessage.BlockVerboseData, error) {
|
||||
|
||||
verboseBlocks := make([]*appmessage.BlockVerboseData, len(blockBytesSlice))
|
||||
for i, blockBytes := range blockBytesSlice {
|
||||
block, err := util.NewBlockFromBytes(blockBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getBlockVerboseResult, err := context.BuildBlockVerboseData(block, includeTransactionVerboseData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verboseBlocks[i] = getBlockVerboseResult
|
||||
}
|
||||
return verboseBlocks, nil
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxBlocksInGetChainFromBlockResponse is the max amount of blocks that
|
||||
// are allowed in a GetChainFromBlockResponse.
|
||||
maxBlocksInGetChainFromBlockResponse = 1000
|
||||
)
|
||||
|
||||
// HandleGetChainFromBlock handles the respectively named RPC command
|
||||
func HandleGetChainFromBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getChainFromBlockRequest := request.(*appmessage.GetChainFromBlockRequestMessage)
|
||||
|
||||
if context.AcceptanceIndex == nil {
|
||||
errorMessage := &appmessage.GetChainFromBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("The acceptance index must be " +
|
||||
"enabled to get the selected parent chain " +
|
||||
"(specify --acceptanceindex)")
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
var startHash *daghash.Hash
|
||||
if getChainFromBlockRequest.StartHash != "" {
|
||||
startHash = &daghash.Hash{}
|
||||
err := daghash.Decode(startHash, getChainFromBlockRequest.StartHash)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetChainFromBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse startHash: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
}
|
||||
|
||||
context.DAG.RLock()
|
||||
defer context.DAG.RUnlock()
|
||||
|
||||
// If startHash is not in the selected parent chain, there's nothing
|
||||
// to do; return an error.
|
||||
if startHash != nil && !context.DAG.IsInDAG(startHash) {
|
||||
errorMessage := &appmessage.GetChainFromBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block %s not found in the DAG", startHash)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
// Retrieve the selected parent chain.
|
||||
removedChainHashes, addedChainHashes, err := context.DAG.SelectedParentChain(startHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Limit the amount of blocks in the response
|
||||
if len(addedChainHashes) > maxBlocksInGetChainFromBlockResponse {
|
||||
addedChainHashes = addedChainHashes[:maxBlocksInGetChainFromBlockResponse]
|
||||
}
|
||||
|
||||
// Collect addedChainBlocks.
|
||||
addedChainBlocks, err := context.CollectChainBlocks(addedChainHashes)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetChainFromBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not collect chain blocks: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
// Collect removedHashes.
|
||||
removedHashes := make([]string, len(removedChainHashes))
|
||||
for i, hash := range removedChainHashes {
|
||||
removedHashes[i] = hash.String()
|
||||
}
|
||||
|
||||
// If the user specified to include the blocks, collect them as well.
|
||||
var blockVerboseData []*appmessage.BlockVerboseData
|
||||
if getChainFromBlockRequest.IncludeBlockVerboseData {
|
||||
data, err := hashesToBlockVerboseData(context, addedChainHashes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockVerboseData = data
|
||||
}
|
||||
|
||||
response := appmessage.NewGetChainFromBlockResponseMessage(removedHashes, addedChainBlocks, blockVerboseData)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// hashesToBlockVerboseData takes block hashes and returns their
|
||||
// correspondent block verbose.
|
||||
func hashesToBlockVerboseData(context *rpccontext.Context, hashes []*daghash.Hash) ([]*appmessage.BlockVerboseData, error) {
|
||||
getBlockVerboseResults := make([]*appmessage.BlockVerboseData, 0, len(hashes))
|
||||
for _, blockHash := range hashes {
|
||||
block, err := context.DAG.BlockByHash(blockHash)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("could not retrieve block %s.", blockHash)
|
||||
}
|
||||
getBlockVerboseResult, err := context.BuildBlockVerboseData(block, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not build getBlockVerboseResult for block %s", blockHash)
|
||||
}
|
||||
getBlockVerboseResults = append(getBlockVerboseResults, getBlockVerboseResult)
|
||||
}
|
||||
return getBlockVerboseResults, nil
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetConnectedPeerInfo handles the respectively named RPC command
|
||||
func HandleGetConnectedPeerInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
peers := context.ProtocolManager.Peers()
|
||||
ibdPeer := context.ProtocolManager.IBDPeer()
|
||||
infos := make([]*appmessage.GetConnectedPeerInfoMessage, 0, len(peers))
|
||||
for _, peer := range peers {
|
||||
info := &appmessage.GetConnectedPeerInfoMessage{
|
||||
ID: peer.ID().String(),
|
||||
Address: peer.Address(),
|
||||
LastPingDuration: peer.LastPingDuration().Milliseconds(),
|
||||
SelectedTipHash: peer.SelectedTipHash().String(),
|
||||
IsSyncNode: peer == ibdPeer,
|
||||
IsOutbound: peer.IsOutbound(),
|
||||
TimeOffset: peer.TimeOffset().Milliseconds(),
|
||||
UserAgent: peer.UserAgent(),
|
||||
AdvertisedProtocolVersion: peer.AdvertisedProtocolVersion(),
|
||||
TimeConnected: peer.TimeConnected().Milliseconds(),
|
||||
}
|
||||
infos = append(infos, info)
|
||||
}
|
||||
response := appmessage.NewGetConnectedPeerInfoResponseMessage(infos)
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetCurrentNetwork handles the respectively named RPC command
|
||||
func HandleGetCurrentNetwork(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
response := appmessage.NewGetCurrentNetworkResponseMessage(context.DAG.Params.Net.String())
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
// HandleGetHeaders handles the respectively named RPC command
|
||||
func HandleGetHeaders(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getHeadersRequest := request.(*appmessage.GetHeadersRequestMessage)
|
||||
dag := context.DAG
|
||||
|
||||
var startHash *daghash.Hash
|
||||
if getHeadersRequest.StartHash != "" {
|
||||
var err error
|
||||
startHash, err = daghash.NewHashFromStr(getHeadersRequest.StartHash)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetHeadersResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Start hash could not be parsed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
}
|
||||
|
||||
const getHeadersDefaultLimit uint64 = 2000
|
||||
limit := getHeadersDefaultLimit
|
||||
if getHeadersRequest.Limit != 0 {
|
||||
limit = getHeadersRequest.Limit
|
||||
}
|
||||
|
||||
headers, err := dag.GetHeaders(startHash, limit, getHeadersRequest.IsAscending)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetHeadersResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Error getting the headers: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
headersHex := make([]string, len(headers))
|
||||
var buf bytes.Buffer
|
||||
for i, header := range headers {
|
||||
err := header.Serialize(&buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
headersHex[i] = hex.EncodeToString(buf.Bytes())
|
||||
buf.Reset()
|
||||
}
|
||||
return appmessage.NewGetHeadersResponseMessage(headersHex), nil
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
// HandleGetMempoolEntry handles the respectively named RPC command
|
||||
func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getMempoolEntryRequest := request.(*appmessage.GetMempoolEntryRequestMessage)
|
||||
txID, err := daghash.NewTxIDFromStr(getMempoolEntryRequest.TxID)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetMempoolEntryResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse txId: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
_, ok := context.Mempool.FetchTxDesc(txID)
|
||||
if !ok {
|
||||
errorMessage := &appmessage.GetMempoolEntryResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("transaction is not in the pool")
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
response := appmessage.NewGetMempoolEntryResponseMessage()
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetPeerAddresses handles the respectively named RPC command
|
||||
func HandleGetPeerAddresses(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
peersState, err := context.AddressManager.PeersStateForSerialization()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addresses := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(peersState.Addresses))
|
||||
for i, address := range peersState.Addresses {
|
||||
addresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: string(address.Address)}
|
||||
}
|
||||
response := appmessage.NewGetPeerAddressesResponseMessage(addresses)
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleGetSelectedTipHash handles the respectively named RPC command
|
||||
func HandleGetSelectedTipHash(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
response := appmessage.NewGetSelectedTipHashResponseMessage(context.DAG.SelectedTipHash().String())
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
)
|
||||
|
||||
// HandleGetSubnetwork handles the respectively named RPC command
|
||||
func HandleGetSubnetwork(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
getSubnetworkRequest := request.(*appmessage.GetSubnetworkRequestMessage)
|
||||
|
||||
subnetworkID, err := subnetworkid.NewFromStr(getSubnetworkRequest.SubnetworkID)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetSubnetworkResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Could not parse subnetworkID: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
var gasLimit uint64
|
||||
if !subnetworkID.IsBuiltInOrNative() {
|
||||
limit, err := context.DAG.GasLimit(subnetworkID)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.GetSubnetworkResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Subnetwork %s not found.", subnetworkID)
|
||||
return errorMessage, nil
|
||||
}
|
||||
gasLimit = limit
|
||||
}
|
||||
|
||||
response := appmessage.NewGetSubnetworkResponseMessage(gasLimit)
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.RPCS)
|
||||
@@ -1,19 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleNotifyBlockAdded handles the respectively named RPC command
|
||||
func HandleNotifyBlockAdded(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
listener, err := context.NotificationManager.Listener(router)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listener.PropagateBlockAddedNotifications()
|
||||
|
||||
response := appmessage.NewNotifyBlockAddedResponseMessage()
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleNotifyChainChanged handles the respectively named RPC command
|
||||
func HandleNotifyChainChanged(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||
if context.AcceptanceIndex == nil {
|
||||
errorMessage := appmessage.NewNotifyChainChangedResponseMessage()
|
||||
errorMessage.Error = appmessage.RPCErrorf("Acceptance index is not available")
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
listener, err := context.NotificationManager.Listener(router)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listener.PropagateChainChangedNotifications()
|
||||
|
||||
response := appmessage.NewNotifyChainChangedResponseMessage()
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
// HandleSubmitBlock handles the respectively named RPC command
|
||||
func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
submitBlockRequest := request.(*appmessage.SubmitBlockRequestMessage)
|
||||
|
||||
// Deserialize the submitted block.
|
||||
serializedBlock, err := hex.DecodeString(submitBlockRequest.BlockHex)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.SubmitBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block hex could not be parsed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
block, err := util.NewBlockFromBytes(serializedBlock)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.SubmitBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block decode failed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
err = context.ProtocolManager.AddBlock(block, blockdag.BFDisallowDelay|blockdag.BFDisallowOrphans)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.SubmitBlockResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Block rejected. Reason: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
log.Infof("Accepted block %s via submitBlock", block.Hash())
|
||||
|
||||
response := appmessage.NewSubmitBlockResponseMessage()
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package rpchandlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// HandleSubmitTransaction handles the respectively named RPC command
|
||||
func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||
submitTransactionRequest := request.(*appmessage.SubmitTransactionRequestMessage)
|
||||
|
||||
serializedTx, err := hex.DecodeString(submitTransactionRequest.TransactionHex)
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.SubmitTransactionResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Transaction hex could not be parsed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
var msgTx appmessage.MsgTx
|
||||
err = msgTx.Deserialize(bytes.NewReader(serializedTx))
|
||||
if err != nil {
|
||||
errorMessage := &appmessage.SubmitTransactionResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Transaction decode failed: %s", err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
tx := util.NewTx(&msgTx)
|
||||
err = context.ProtocolManager.AddTransaction(tx)
|
||||
if err != nil {
|
||||
if !errors.As(err, &mempool.RuleError{}) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Rejected transaction %s: %s", tx.ID(), err)
|
||||
errorMessage := &appmessage.SubmitTransactionResponseMessage{}
|
||||
errorMessage.Error = appmessage.RPCErrorf("Rejected transaction %s: %s", tx.ID(), err)
|
||||
return errorMessage, nil
|
||||
}
|
||||
|
||||
response := appmessage.NewSubmitTransactionResponseMessage(tx.ID().String())
|
||||
return response, nil
|
||||
}
|
||||
154
blockdag/accept.go
Normal file
154
blockdag/accept.go
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (dag *BlockDAG) addNodeToIndexWithInvalidAncestor(block *util.Block) error {
|
||||
blockHeader := &block.MsgBlock().Header
|
||||
newNode, _ := dag.newBlockNode(blockHeader, newBlockSet())
|
||||
newNode.status = statusInvalidAncestor
|
||||
dag.index.AddNode(newNode)
|
||||
|
||||
dbTx, err := dag.databaseContext.NewTx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbTx.RollbackUnlessClosed()
|
||||
err = dag.index.flushToDB(dbTx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dbTx.Commit()
|
||||
}
|
||||
|
||||
// maybeAcceptBlock potentially accepts a block into the block DAG. It
|
||||
// performs several validation checks which depend on its position within
|
||||
// the block DAG before adding it. The block is expected to have already
|
||||
// gone through ProcessBlock before calling this function with it.
|
||||
//
|
||||
// The flags are also passed to checkBlockContext and connectToDAG. See
|
||||
// their documentation for how the flags modify their behavior.
|
||||
//
|
||||
// This function MUST be called with the dagLock held (for writes).
|
||||
func (dag *BlockDAG) maybeAcceptBlock(block *util.Block, flags BehaviorFlags) error {
|
||||
parents, err := lookupParentNodes(block, dag)
|
||||
if err != nil {
|
||||
var ruleErr RuleError
|
||||
if ok := errors.As(err, &ruleErr); ok && ruleErr.ErrorCode == ErrInvalidAncestorBlock {
|
||||
err := dag.addNodeToIndexWithInvalidAncestor(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// The block must pass all of the validation rules which depend on the
|
||||
// position of the block within the block DAG.
|
||||
err = dag.checkBlockContext(block, parents, flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a new block node for the block and add it to the node index.
|
||||
newNode, selectedParentAnticone := dag.newBlockNode(&block.MsgBlock().Header, parents)
|
||||
newNode.status = statusDataStored
|
||||
dag.index.AddNode(newNode)
|
||||
|
||||
// Insert the block into the database if it's not already there. Even
|
||||
// though it is possible the block will ultimately fail to connect, it
|
||||
// has already passed all proof-of-work and validity tests which means
|
||||
// it would be prohibitively expensive for an attacker to fill up the
|
||||
// disk with a bunch of blocks that fail to connect. This is necessary
|
||||
// since it allows block download to be decoupled from the much more
|
||||
// expensive connection logic. It also has some other nice properties
|
||||
// such as making blocks that never become part of the DAG or
|
||||
// blocks that fail to connect available for further analysis.
|
||||
dbTx, err := dag.databaseContext.NewTx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbTx.RollbackUnlessClosed()
|
||||
blockExists, err := dbaccess.HasBlock(dbTx, block.Hash())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !blockExists {
|
||||
err := storeBlock(dbTx, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = dag.index.flushToDB(dbTx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbTx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure that all the block's transactions are finalized
|
||||
fastAdd := flags&BFFastAdd == BFFastAdd
|
||||
bluestParent := parents.bluest()
|
||||
if !fastAdd {
|
||||
if err := dag.validateAllTxsFinalized(block, newNode, bluestParent); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the passed block to the DAG. This also handles validation of the
|
||||
// transaction scripts.
|
||||
chainUpdates, err := dag.addBlock(newNode, block, selectedParentAnticone, flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify the caller that the new block was accepted into the block
|
||||
// DAG. The caller would typically want to react by relaying the
|
||||
// inventory to other peers.
|
||||
dag.dagLock.Unlock()
|
||||
dag.sendNotification(NTBlockAdded, &BlockAddedNotificationData{
|
||||
Block: block,
|
||||
WasUnorphaned: flags&BFWasUnorphaned != 0,
|
||||
})
|
||||
if len(chainUpdates.addedChainBlockHashes) > 0 {
|
||||
dag.sendNotification(NTChainChanged, &ChainChangedNotificationData{
|
||||
RemovedChainBlockHashes: chainUpdates.removedChainBlockHashes,
|
||||
AddedChainBlockHashes: chainUpdates.addedChainBlockHashes,
|
||||
})
|
||||
}
|
||||
dag.dagLock.Lock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupParentNodes(block *util.Block, dag *BlockDAG) (blockSet, error) {
|
||||
header := block.MsgBlock().Header
|
||||
parentHashes := header.ParentHashes
|
||||
|
||||
nodes := newBlockSet()
|
||||
for _, parentHash := range parentHashes {
|
||||
node, ok := dag.index.LookupNode(parentHash)
|
||||
if !ok {
|
||||
str := fmt.Sprintf("parent block %s is unknown", parentHash)
|
||||
return nil, ruleError(ErrParentBlockUnknown, str)
|
||||
} else if dag.index.NodeStatus(node).KnownInvalid() {
|
||||
str := fmt.Sprintf("parent block %s is known to be invalid", parentHash)
|
||||
return nil, ruleError(ErrInvalidAncestorBlock, str)
|
||||
}
|
||||
|
||||
nodes.add(node)
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
107
blockdag/accept_test.go
Normal file
107
blockdag/accept_test.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
)
|
||||
|
||||
func TestMaybeAcceptBlockErrors(t *testing.T) {
|
||||
// Create a new database and DAG instance to run tests against.
|
||||
dag, teardownFunc, err := DAGSetup("TestMaybeAcceptBlockErrors", true, Config{
|
||||
DAGParams: &dagconfig.SimnetParams,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: Failed to setup DAG instance: %v", err)
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
dag.TestSetCoinbaseMaturity(0)
|
||||
|
||||
// Test rejecting the block if its parents are missing
|
||||
orphanBlockFile := "blk_3B.dat"
|
||||
loadedBlocks, err := LoadBlocks(filepath.Join("testdata/", orphanBlockFile))
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: "+
|
||||
"Error loading file '%s': %s\n", orphanBlockFile, err)
|
||||
}
|
||||
block := loadedBlocks[0]
|
||||
|
||||
err = dag.maybeAcceptBlock(block, BFNone)
|
||||
if err == nil {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are missing: "+
|
||||
"Expected: %s, got: <nil>", ErrParentBlockUnknown)
|
||||
}
|
||||
var ruleErr RuleError
|
||||
if ok := errors.As(err, &ruleErr); !ok {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are missing: "+
|
||||
"Expected RuleError but got %s", err)
|
||||
} else if ruleErr.ErrorCode != ErrParentBlockUnknown {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are missing: "+
|
||||
"Unexpected error code. Want: %s, got: %s", ErrParentBlockUnknown, ruleErr.ErrorCode)
|
||||
}
|
||||
|
||||
// Test rejecting the block if its parents are invalid
|
||||
blocksFile := "blk_0_to_4.dat"
|
||||
blocks, err := LoadBlocks(filepath.Join("testdata/", blocksFile))
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: "+
|
||||
"Error loading file '%s': %s\n", blocksFile, err)
|
||||
}
|
||||
|
||||
// Add a valid block and mark it as invalid
|
||||
block1 := blocks[1]
|
||||
isOrphan, isDelayed, err := dag.ProcessBlock(block1, BFNone)
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: Valid block unexpectedly returned an error: %s", err)
|
||||
}
|
||||
if isDelayed {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: block 1 is too far in the future")
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: incorrectly returned block 1 is an orphan")
|
||||
}
|
||||
blockNode1, ok := dag.index.LookupNode(block1.Hash())
|
||||
if !ok {
|
||||
t.Fatalf("block %s does not exist in the DAG", block1.Hash())
|
||||
}
|
||||
dag.index.SetStatusFlags(blockNode1, statusValidateFailed)
|
||||
|
||||
block2 := blocks[2]
|
||||
err = dag.maybeAcceptBlock(block2, BFNone)
|
||||
if err == nil {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are invalid: "+
|
||||
"Expected: %s, got: <nil>", ErrInvalidAncestorBlock)
|
||||
}
|
||||
if ok := errors.As(err, &ruleErr); !ok {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are invalid: "+
|
||||
"Expected RuleError but got %s", err)
|
||||
} else if ruleErr.ErrorCode != ErrInvalidAncestorBlock {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are invalid: "+
|
||||
"Unexpected error. Want: %s, got: %s", ErrInvalidAncestorBlock, ruleErr.ErrorCode)
|
||||
}
|
||||
|
||||
// Set block1's status back to valid for next tests
|
||||
dag.index.UnsetStatusFlags(blockNode1, statusValidateFailed)
|
||||
|
||||
// Test rejecting the block due to bad context
|
||||
originalBits := block2.MsgBlock().Header.Bits
|
||||
block2.MsgBlock().Header.Bits = 0
|
||||
err = dag.maybeAcceptBlock(block2, BFNone)
|
||||
if err == nil {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block due to bad context: "+
|
||||
"Expected: %s, got: <nil>", ErrUnexpectedDifficulty)
|
||||
}
|
||||
if ok := errors.As(err, &ruleErr); !ok {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block due to bad context: "+
|
||||
"Expected RuleError but got %s", err)
|
||||
} else if ruleErr.ErrorCode != ErrUnexpectedDifficulty {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block due to bad context: "+
|
||||
"Unexpected error. Want: %s, got: %s", ErrUnexpectedDifficulty, ruleErr.ErrorCode)
|
||||
}
|
||||
|
||||
// Set block2's bits back to valid for next tests
|
||||
block2.MsgBlock().Header.Bits = originalBits
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package blockdag
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
@@ -5,12 +5,10 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"sync"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
@@ -136,42 +134,3 @@ func (bi *blockIndex) flushToDB(dbContext *dbaccess.TxContext) error {
|
||||
func (bi *blockIndex) clearDirtyEntries() {
|
||||
bi.dirty = make(map[*blockNode]struct{})
|
||||
}
|
||||
|
||||
func (dag *BlockDAG) addNodeToIndexWithInvalidAncestor(block *util.Block) error {
|
||||
blockHeader := &block.MsgBlock().Header
|
||||
newNode, _ := dag.newBlockNode(blockHeader, newBlockSet())
|
||||
newNode.status = statusInvalidAncestor
|
||||
dag.index.AddNode(newNode)
|
||||
|
||||
dbTx, err := dag.databaseContext.NewTx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbTx.RollbackUnlessClosed()
|
||||
err = dag.index.flushToDB(dbTx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dbTx.Commit()
|
||||
}
|
||||
|
||||
func lookupParentNodes(block *util.Block, dag *BlockDAG) (blockSet, error) {
|
||||
header := block.MsgBlock().Header
|
||||
parentHashes := header.ParentHashes
|
||||
|
||||
nodes := newBlockSet()
|
||||
for _, parentHash := range parentHashes {
|
||||
node, ok := dag.index.LookupNode(parentHash)
|
||||
if !ok {
|
||||
str := fmt.Sprintf("parent block %s is unknown", parentHash)
|
||||
return nil, ruleError(ErrParentBlockUnknown, str)
|
||||
} else if dag.index.NodeStatus(node).KnownInvalid() {
|
||||
str := fmt.Sprintf("parent block %s is known to be invalid", parentHash)
|
||||
return nil, ruleError(ErrInvalidAncestorBlock, str)
|
||||
}
|
||||
|
||||
nodes.add(node)
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"testing"
|
||||
)
|
||||
109
blockdag/blocklocator.go
Normal file
109
blockdag/blocklocator.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// BlockLocator is used to help locate a specific block. The algorithm for
|
||||
// building the block locator is to add block hashes in reverse order on the
|
||||
// block's selected parent chain until the desired stop block is reached.
|
||||
// In order to keep the list of locator hashes to a reasonable number of entries,
|
||||
// the step between each entry is doubled each loop iteration to exponentially
|
||||
// decrease the number of hashes as a function of the distance from the block
|
||||
// being located.
|
||||
//
|
||||
// For example, assume a selected parent chain with IDs as depicted below, and the
|
||||
// stop block is genesis:
|
||||
// genesis -> 1 -> 2 -> ... -> 15 -> 16 -> 17 -> 18
|
||||
//
|
||||
// The block locator for block 17 would be the hashes of blocks:
|
||||
// [17 16 14 11 7 2 genesis]
|
||||
type BlockLocator []*daghash.Hash
|
||||
|
||||
// BlockLocatorFromHashes returns a block locator from high and low hash.
|
||||
// See BlockLocator for details on the algorithm used to create a block locator.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (dag *BlockDAG) BlockLocatorFromHashes(highHash, lowHash *daghash.Hash) (BlockLocator, error) {
|
||||
dag.dagLock.RLock()
|
||||
defer dag.dagLock.RUnlock()
|
||||
|
||||
highNode, ok := dag.index.LookupNode(highHash)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("block %s is unknown", highHash)
|
||||
}
|
||||
|
||||
lowNode, ok := dag.index.LookupNode(lowHash)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("block %s is unknown", lowHash)
|
||||
}
|
||||
|
||||
return dag.blockLocator(highNode, lowNode)
|
||||
}
|
||||
|
||||
// blockLocator returns a block locator for the passed high and low nodes.
|
||||
// See the BlockLocator type comments for more details.
|
||||
//
|
||||
// This function MUST be called with the DAG state lock held (for reads).
|
||||
func (dag *BlockDAG) blockLocator(highNode, lowNode *blockNode) (BlockLocator, error) {
|
||||
// We use the selected parent of the high node, so the
|
||||
// block locator won't contain the high node.
|
||||
highNode = highNode.selectedParent
|
||||
|
||||
node := highNode
|
||||
step := uint64(1)
|
||||
locator := make(BlockLocator, 0)
|
||||
for node != nil {
|
||||
locator = append(locator, node.hash)
|
||||
|
||||
// Nothing more to add once the low node has been added.
|
||||
if node.blueScore <= lowNode.blueScore {
|
||||
if node != lowNode {
|
||||
return nil, errors.Errorf("highNode and lowNode are " +
|
||||
"not in the same selected parent chain.")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Calculate blueScore of previous node to include ensuring the
|
||||
// final node is lowNode.
|
||||
nextBlueScore := node.blueScore - step
|
||||
if nextBlueScore < lowNode.blueScore {
|
||||
nextBlueScore = lowNode.blueScore
|
||||
}
|
||||
|
||||
// walk backwards through the nodes to the correct ancestor.
|
||||
node = node.SelectedAncestor(nextBlueScore)
|
||||
|
||||
// Double the distance between included hashes.
|
||||
step *= 2
|
||||
}
|
||||
|
||||
return locator, nil
|
||||
}
|
||||
|
||||
// FindNextLocatorBoundaries returns the lowest unknown block locator, hash
|
||||
// and the highest known block locator hash. This is used to create the
|
||||
// next block locator to find the highest shared known chain block with the
|
||||
// sync peer.
|
||||
//
|
||||
// This function MUST be called with the DAG state lock held (for reads).
|
||||
func (dag *BlockDAG) FindNextLocatorBoundaries(locator BlockLocator) (highHash, lowHash *daghash.Hash) {
|
||||
// Find the most recent locator block hash in the DAG. In the case none of
|
||||
// the hashes in the locator are in the DAG, fall back to the genesis block.
|
||||
lowNode := dag.genesis
|
||||
nextBlockLocatorIndex := int64(len(locator) - 1)
|
||||
for i, hash := range locator {
|
||||
node, ok := dag.index.LookupNode(hash)
|
||||
if ok {
|
||||
lowNode = node
|
||||
nextBlockLocatorIndex = int64(i) - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if nextBlockLocatorIndex < 0 {
|
||||
return nil, lowNode.hash
|
||||
}
|
||||
return locator[nextBlockLocatorIndex], lowNode.hash
|
||||
}
|
||||
@@ -8,11 +8,11 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ type blockNode struct {
|
||||
// anticone of its selected parent (parent with highest blue score).
|
||||
// selectedParentAnticone is used to update reachability data we store for future reachability queries.
|
||||
// This function is NOT safe for concurrent access.
|
||||
func (dag *BlockDAG) newBlockNode(blockHeader *appmessage.BlockHeader, parents blockSet) (node *blockNode, selectedParentAnticone []*blockNode) {
|
||||
func (dag *BlockDAG) newBlockNode(blockHeader *domainmessage.BlockHeader, parents blockSet) (node *blockNode, selectedParentAnticone []*blockNode) {
|
||||
node = &blockNode{
|
||||
parents: parents,
|
||||
children: make(blockSet),
|
||||
@@ -160,9 +160,9 @@ func (node *blockNode) less(other *blockNode) bool {
|
||||
// Header constructs a block header from the node and returns it.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (node *blockNode) Header() *appmessage.BlockHeader {
|
||||
func (node *blockNode) Header() *domainmessage.BlockHeader {
|
||||
// No lock is needed because all accessed fields are immutable.
|
||||
return &appmessage.BlockHeader{
|
||||
return &domainmessage.BlockHeader{
|
||||
Version: node.version,
|
||||
ParentHashes: node.ParentHashes(),
|
||||
HashMerkleRoot: node.hashMerkleRoot,
|
||||
@@ -1,7 +1,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"testing"
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
"reflect"
|
||||
@@ -51,14 +51,14 @@ func TestBlueBlockWindow(t *testing.T) {
|
||||
expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"C", "D"},
|
||||
parents: []string{"D", "C"},
|
||||
id: "E",
|
||||
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"C", "D"},
|
||||
parents: []string{"D", "C"},
|
||||
id: "F",
|
||||
expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"A"},
|
||||
@@ -73,37 +73,37 @@ func TestBlueBlockWindow(t *testing.T) {
|
||||
{
|
||||
parents: []string{"H", "F"},
|
||||
id: "I",
|
||||
expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"I"},
|
||||
id: "J",
|
||||
expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"J"},
|
||||
id: "K",
|
||||
expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"K"},
|
||||
id: "L",
|
||||
expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"L"},
|
||||
id: "M",
|
||||
expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "N",
|
||||
expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"},
|
||||
expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"N"},
|
||||
id: "O",
|
||||
expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"},
|
||||
expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/coinbasepayload"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -124,8 +124,8 @@ func (node *blockNode) expectedCoinbaseTransaction(dag *BlockDAG, txsAcceptanceD
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txIns := []*appmessage.TxIn{}
|
||||
txOuts := []*appmessage.TxOut{}
|
||||
txIns := []*domainmessage.TxIn{}
|
||||
txOuts := []*domainmessage.TxOut{}
|
||||
|
||||
for _, blue := range node.blues {
|
||||
txOut, err := coinbaseOutputForBlueBlock(dag, blue, txsAcceptanceData, bluesFeeData)
|
||||
@@ -140,7 +140,7 @@ func (node *blockNode) expectedCoinbaseTransaction(dag *BlockDAG, txsAcceptanceD
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
coinbaseTx := appmessage.NewSubnetworkMsgTx(appmessage.TxVersion, txIns, txOuts, subnetworkid.SubnetworkIDCoinbase, 0, payload)
|
||||
coinbaseTx := domainmessage.NewSubnetworkMsgTx(domainmessage.TxVersion, txIns, txOuts, subnetworkid.SubnetworkIDCoinbase, 0, payload)
|
||||
sortedCoinbaseTx := txsort.Sort(coinbaseTx)
|
||||
return util.NewTx(sortedCoinbaseTx), nil
|
||||
}
|
||||
@@ -148,7 +148,7 @@ func (node *blockNode) expectedCoinbaseTransaction(dag *BlockDAG, txsAcceptanceD
|
||||
// coinbaseOutputForBlueBlock calculates the output that should go into the coinbase transaction of blueBlock
|
||||
// If blueBlock gets no fee - returns nil for txOut
|
||||
func coinbaseOutputForBlueBlock(dag *BlockDAG, blueBlock *blockNode,
|
||||
txsAcceptanceData MultiBlockTxsAcceptanceData, feeData map[daghash.Hash]compactFeeData) (*appmessage.TxOut, error) {
|
||||
txsAcceptanceData MultiBlockTxsAcceptanceData, feeData map[daghash.Hash]compactFeeData) (*domainmessage.TxOut, error) {
|
||||
|
||||
blockTxsAcceptanceData, ok := txsAcceptanceData.FindAcceptanceData(blueBlock.hash)
|
||||
if !ok {
|
||||
@@ -190,31 +190,10 @@ func coinbaseOutputForBlueBlock(dag *BlockDAG, blueBlock *blockNode,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txOut := &appmessage.TxOut{
|
||||
txOut := &domainmessage.TxOut{
|
||||
Value: totalReward,
|
||||
ScriptPubKey: scriptPubKey,
|
||||
}
|
||||
|
||||
return txOut, nil
|
||||
}
|
||||
|
||||
// NextBlockCoinbaseTransaction prepares the coinbase transaction for the next mined block
|
||||
//
|
||||
// This function CAN'T be called with the DAG lock held.
|
||||
func (dag *BlockDAG) NextBlockCoinbaseTransaction(scriptPubKey []byte, extraData []byte) (*util.Tx, error) {
|
||||
dag.dagLock.RLock()
|
||||
defer dag.dagLock.RUnlock()
|
||||
|
||||
return dag.NextBlockCoinbaseTransactionNoLock(scriptPubKey, extraData)
|
||||
}
|
||||
|
||||
// NextBlockCoinbaseTransactionNoLock prepares the coinbase transaction for the next mined block
|
||||
//
|
||||
// This function MUST be called with the DAG read-lock held
|
||||
func (dag *BlockDAG) NextBlockCoinbaseTransactionNoLock(scriptPubKey []byte, extraData []byte) (*util.Tx, error) {
|
||||
txsAcceptanceData, err := dag.TxsAcceptedByVirtual()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dag.virtual.blockNode.expectedCoinbaseTransaction(dag, txsAcceptanceData, scriptPubKey, extraData)
|
||||
}
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
@@ -78,7 +78,7 @@ func loadUTXOSet(filename string) (UTXOSet, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utxoSet.utxoCollection[appmessage.Outpoint{TxID: txID, Index: index}] = entry
|
||||
utxoSet.utxoCollection[domainmessage.Outpoint{TxID: txID, Index: index}] = entry
|
||||
}
|
||||
|
||||
return utxoSet, nil
|
||||
@@ -103,6 +103,8 @@ func newTestDAG(params *dagconfig.Params) *BlockDAG {
|
||||
TimestampDeviationTolerance: params.TimestampDeviationTolerance,
|
||||
powMaxBits: util.BigToCompact(params.PowMax),
|
||||
index: index,
|
||||
warningCaches: newThresholdCaches(vbNumBits),
|
||||
deploymentCaches: newThresholdCaches(dagconfig.DefinedDeployments),
|
||||
}
|
||||
|
||||
// Create a genesis block node and block index index populated with it
|
||||
@@ -118,7 +120,7 @@ func newTestDAG(params *dagconfig.Params) *BlockDAG {
|
||||
// provided fields populated and fake values for the other fields.
|
||||
func newTestNode(dag *BlockDAG, parents blockSet, blockVersion int32, bits uint32, timestamp mstime.Time) *blockNode {
|
||||
// Make up a header and create a block node from it.
|
||||
header := &appmessage.BlockHeader{
|
||||
header := &domainmessage.BlockHeader{
|
||||
Version: blockVersion,
|
||||
ParentHashes: parents.hashes(),
|
||||
Bits: bits,
|
||||
@@ -166,7 +168,7 @@ func checkRuleError(gotErr, wantErr error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func prepareAndProcessBlockByParentMsgBlocks(t *testing.T, dag *BlockDAG, parents ...*appmessage.MsgBlock) *appmessage.MsgBlock {
|
||||
func prepareAndProcessBlockByParentMsgBlocks(t *testing.T, dag *BlockDAG, parents ...*domainmessage.MsgBlock) *domainmessage.MsgBlock {
|
||||
parentHashes := make([]*daghash.Hash, len(parents))
|
||||
for i, parent := range parents {
|
||||
parentHashes[i] = parent.BlockHash()
|
||||
@@ -174,7 +176,7 @@ func prepareAndProcessBlockByParentMsgBlocks(t *testing.T, dag *BlockDAG, parent
|
||||
return PrepareAndProcessBlockForTest(t, dag, parentHashes, nil)
|
||||
}
|
||||
|
||||
func nodeByMsgBlock(t *testing.T, dag *BlockDAG, block *appmessage.MsgBlock) *blockNode {
|
||||
func nodeByMsgBlock(t *testing.T, dag *BlockDAG, block *domainmessage.MsgBlock) *blockNode {
|
||||
node, ok := dag.index.LookupNode(block.BlockHash())
|
||||
if !ok {
|
||||
t.Fatalf("couldn't find block node with hash %s", block.BlockHash())
|
||||
2143
blockdag/dag.go
Normal file
2143
blockdag/dag.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,12 +14,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/go-secp256k1"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domain/txscript"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
@@ -214,7 +214,7 @@ func TestIsKnownBlock(t *testing.T) {
|
||||
{hash: "732c891529619d43b5aeb3df42ba25dea483a8c0aded1cf585751ebabea28f29", want: true},
|
||||
|
||||
// Random hashes should not be available.
|
||||
{hash: "1234567812345678123456781234567812345678123456781234567812345678", want: false},
|
||||
{hash: "123", want: false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
@@ -255,7 +255,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// Create a utxo view with a fake utxo for the inputs used in the
|
||||
// transactions created below. This utxo is added such that it has an
|
||||
// age of 4 blocks.
|
||||
msgTx := appmessage.NewNativeMsgTx(appmessage.TxVersion, nil, []*appmessage.TxOut{{ScriptPubKey: nil, Value: 10}})
|
||||
msgTx := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, nil, []*domainmessage.TxOut{{ScriptPubKey: nil, Value: 10}})
|
||||
targetTx := util.NewTx(msgTx)
|
||||
utxoSet := NewFullUTXOSet()
|
||||
blueScore := uint64(numBlocksToGenerate) - 4
|
||||
@@ -270,7 +270,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// that the sequence lock heights are always calculated from the same
|
||||
// point of view that they were originally calculated from for a given
|
||||
// utxo. That is to say, the height prior to it.
|
||||
utxo := appmessage.Outpoint{
|
||||
utxo := domainmessage.Outpoint{
|
||||
TxID: *targetTx.ID(),
|
||||
Index: 0,
|
||||
}
|
||||
@@ -290,8 +290,8 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
|
||||
// Add an additional transaction which will serve as our unconfirmed
|
||||
// output.
|
||||
unConfTx := appmessage.NewNativeMsgTx(appmessage.TxVersion, nil, []*appmessage.TxOut{{ScriptPubKey: nil, Value: 5}})
|
||||
unConfUtxo := appmessage.Outpoint{
|
||||
unConfTx := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, nil, []*domainmessage.TxOut{{ScriptPubKey: nil, Value: 5}})
|
||||
unConfUtxo := domainmessage.Outpoint{
|
||||
TxID: *unConfTx.TxID(),
|
||||
Index: 0,
|
||||
}
|
||||
@@ -303,8 +303,9 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tx *appmessage.MsgTx
|
||||
tx *domainmessage.MsgTx
|
||||
utxoSet UTXOSet
|
||||
mempool bool
|
||||
want *SequenceLock
|
||||
}{
|
||||
// A transaction with a single input with max sequence number.
|
||||
@@ -312,7 +313,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// should be disabled.
|
||||
{
|
||||
name: "single input, max sequence number",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{PreviousOutpoint: utxo, Sequence: appmessage.MaxTxInSequenceNum}}, nil),
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{PreviousOutpoint: utxo, Sequence: domainmessage.MaxTxInSequenceNum}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: -1,
|
||||
@@ -327,7 +328,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// the targeted block.
|
||||
{
|
||||
name: "single input, milliseconds lock time below time granularity",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{PreviousOutpoint: utxo, Sequence: LockTimeToSequence(true, 2)}}, nil),
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{PreviousOutpoint: utxo, Sequence: LockTimeToSequence(true, 2)}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: medianTime - 1,
|
||||
@@ -339,7 +340,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// milliseconds after the median past time of the DAG.
|
||||
{
|
||||
name: "single input, 1048575 milliseconds after median time",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{PreviousOutpoint: utxo, Sequence: LockTimeToSequence(true, 1048576)}}, nil),
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{PreviousOutpoint: utxo, Sequence: LockTimeToSequence(true, 1048576)}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: medianTime + 1048575,
|
||||
@@ -354,8 +355,8 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// latest lock that isn't disabled.
|
||||
{
|
||||
name: "multiple varied inputs",
|
||||
tx: appmessage.NewNativeMsgTx(1,
|
||||
[]*appmessage.TxIn{{
|
||||
tx: domainmessage.NewNativeMsgTx(1,
|
||||
[]*domainmessage.TxIn{{
|
||||
PreviousOutpoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 2621440),
|
||||
}, {
|
||||
@@ -364,12 +365,12 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
}, {
|
||||
PreviousOutpoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 5) |
|
||||
appmessage.SequenceLockTimeDisabled,
|
||||
domainmessage.SequenceLockTimeDisabled,
|
||||
}},
|
||||
nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: medianTime + (5 << appmessage.SequenceLockTimeGranularity) - 1,
|
||||
Milliseconds: medianTime + (5 << domainmessage.SequenceLockTimeGranularity) - 1,
|
||||
BlockBlueScore: int64(prevUtxoBlueScore) + 3,
|
||||
},
|
||||
},
|
||||
@@ -379,7 +380,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// height of 2 meaning it can be included at height 3.
|
||||
{
|
||||
name: "single input, lock-time in blocks",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{PreviousOutpoint: utxo, Sequence: LockTimeToSequence(false, 3)}}, nil),
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{PreviousOutpoint: utxo, Sequence: LockTimeToSequence(false, 3)}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: -1,
|
||||
@@ -391,7 +392,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// be the time further in the future.
|
||||
{
|
||||
name: "two inputs, lock-times in seconds",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{
|
||||
PreviousOutpoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 5242880),
|
||||
}, {
|
||||
@@ -400,7 +401,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: medianTime + (10 << appmessage.SequenceLockTimeGranularity) - 1,
|
||||
Milliseconds: medianTime + (10 << domainmessage.SequenceLockTimeGranularity) - 1,
|
||||
BlockBlueScore: -1,
|
||||
},
|
||||
},
|
||||
@@ -410,8 +411,8 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// indicating it can be included at height 11.
|
||||
{
|
||||
name: "two inputs, lock-times in blocks",
|
||||
tx: appmessage.NewNativeMsgTx(1,
|
||||
[]*appmessage.TxIn{{
|
||||
tx: domainmessage.NewNativeMsgTx(1,
|
||||
[]*domainmessage.TxIn{{
|
||||
PreviousOutpoint: utxo,
|
||||
Sequence: LockTimeToSequence(false, 1),
|
||||
}, {
|
||||
@@ -430,8 +431,8 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// further into the future for both inputs should be chosen.
|
||||
{
|
||||
name: "four inputs, two lock-times in time, two lock-times in blocks",
|
||||
tx: appmessage.NewNativeMsgTx(1,
|
||||
[]*appmessage.TxIn{{
|
||||
tx: domainmessage.NewNativeMsgTx(1,
|
||||
[]*domainmessage.TxIn{{
|
||||
PreviousOutpoint: utxo,
|
||||
Sequence: LockTimeToSequence(true, 2621440),
|
||||
}, {
|
||||
@@ -447,7 +448,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
nil),
|
||||
utxoSet: utxoSet,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: medianTime + (13 << appmessage.SequenceLockTimeGranularity) - 1,
|
||||
Milliseconds: medianTime + (13 << domainmessage.SequenceLockTimeGranularity) - 1,
|
||||
BlockBlueScore: int64(prevUtxoBlueScore) + 8,
|
||||
},
|
||||
},
|
||||
@@ -459,8 +460,9 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// after that.
|
||||
{
|
||||
name: "single input, unconfirmed, lock-time in blocks",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{PreviousOutpoint: unConfUtxo, Sequence: LockTimeToSequence(false, 2)}}, nil),
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{PreviousOutpoint: unConfUtxo, Sequence: LockTimeToSequence(false, 2)}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
mempool: true,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: -1,
|
||||
BlockBlueScore: int64(nextBlockBlueScore) + 1,
|
||||
@@ -471,8 +473,9 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
// MTP of the *next* block.
|
||||
{
|
||||
name: "single input, unconfirmed, lock-time in milliseoncds",
|
||||
tx: appmessage.NewNativeMsgTx(1, []*appmessage.TxIn{{PreviousOutpoint: unConfUtxo, Sequence: LockTimeToSequence(true, 1048576)}}, nil),
|
||||
tx: domainmessage.NewNativeMsgTx(1, []*domainmessage.TxIn{{PreviousOutpoint: unConfUtxo, Sequence: LockTimeToSequence(true, 1048576)}}, nil),
|
||||
utxoSet: utxoSet,
|
||||
mempool: true,
|
||||
want: &SequenceLock{
|
||||
Milliseconds: nextMedianTime + 1048575,
|
||||
BlockBlueScore: -1,
|
||||
@@ -483,7 +486,7 @@ func TestCalcSequenceLock(t *testing.T) {
|
||||
t.Logf("Running %v SequenceLock tests", len(tests))
|
||||
for _, test := range tests {
|
||||
utilTx := util.NewTx(test.tx)
|
||||
seqLock, err := dag.CalcSequenceLock(utilTx, utxoSet)
|
||||
seqLock, err := dag.CalcSequenceLock(utilTx, utxoSet, test.mempool)
|
||||
if err != nil {
|
||||
t.Fatalf("test '%s', unable to calc sequence lock: %v", test.name, err)
|
||||
}
|
||||
@@ -698,7 +701,7 @@ func TestConfirmations(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add a chain of blocks
|
||||
chainBlocks := make([]*appmessage.MsgBlock, 5)
|
||||
chainBlocks := make([]*domainmessage.MsgBlock, 5)
|
||||
chainBlocks[0] = dag.Params.GenesisBlock
|
||||
for i := uint32(1); i < 5; i++ {
|
||||
chainBlocks[i] = prepareAndProcessBlockByParentMsgBlocks(t, dag, chainBlocks[i-1])
|
||||
@@ -718,7 +721,7 @@ func TestConfirmations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
branchingBlocks := make([]*appmessage.MsgBlock, 2)
|
||||
branchingBlocks := make([]*domainmessage.MsgBlock, 2)
|
||||
// Add two branching blocks
|
||||
branchingBlocks[0] = prepareAndProcessBlockByParentMsgBlocks(t, dag, chainBlocks[1])
|
||||
branchingBlocks[1] = prepareAndProcessBlockByParentMsgBlocks(t, dag, branchingBlocks[0])
|
||||
@@ -791,7 +794,7 @@ func TestAcceptingBlock(t *testing.T) {
|
||||
defer teardownFunc()
|
||||
dag.TestSetCoinbaseMaturity(0)
|
||||
|
||||
acceptingBlockByMsgBlock := func(block *appmessage.MsgBlock) (*blockNode, error) {
|
||||
acceptingBlockByMsgBlock := func(block *domainmessage.MsgBlock) (*blockNode, error) {
|
||||
node := nodeByMsgBlock(t, dag, block)
|
||||
return dag.acceptingBlock(node)
|
||||
}
|
||||
@@ -807,7 +810,7 @@ func TestAcceptingBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
numChainBlocks := uint32(10)
|
||||
chainBlocks := make([]*appmessage.MsgBlock, numChainBlocks)
|
||||
chainBlocks := make([]*domainmessage.MsgBlock, numChainBlocks)
|
||||
chainBlocks[0] = dag.Params.GenesisBlock
|
||||
for i := uint32(1); i <= numChainBlocks-1; i++ {
|
||||
chainBlocks[i] = prepareAndProcessBlockByParentMsgBlocks(t, dag, chainBlocks[i-1])
|
||||
@@ -1027,11 +1030,11 @@ func TestDAGIndexFailedStatus(t *testing.T) {
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
invalidCbTx := appmessage.NewSubnetworkMsgTx(appmessage.TxVersion, []*appmessage.TxIn{}, []*appmessage.TxOut{}, subnetworkid.SubnetworkIDCoinbase, 0, []byte{})
|
||||
invalidCbTx := domainmessage.NewSubnetworkMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{}, []*domainmessage.TxOut{}, subnetworkid.SubnetworkIDCoinbase, 0, []byte{})
|
||||
txs := []*util.Tx{util.NewTx(invalidCbTx)}
|
||||
hashMerkleRoot := BuildHashMerkleTreeStore(txs).Root()
|
||||
invalidMsgBlock := appmessage.NewMsgBlock(
|
||||
appmessage.NewBlockHeader(
|
||||
invalidMsgBlock := domainmessage.NewMsgBlock(
|
||||
domainmessage.NewBlockHeader(
|
||||
1,
|
||||
[]*daghash.Hash{params.GenesisHash}, hashMerkleRoot,
|
||||
&daghash.Hash{},
|
||||
@@ -1063,8 +1066,8 @@ func TestDAGIndexFailedStatus(t *testing.T) {
|
||||
t.Fatalf("invalidBlockNode status to have %b flags raised (got: %b)", statusValidateFailed, invalidBlockNode.status)
|
||||
}
|
||||
|
||||
invalidMsgBlockChild := appmessage.NewMsgBlock(
|
||||
appmessage.NewBlockHeader(1, []*daghash.Hash{
|
||||
invalidMsgBlockChild := domainmessage.NewMsgBlock(
|
||||
domainmessage.NewBlockHeader(1, []*daghash.Hash{
|
||||
invalidBlock.Hash(),
|
||||
}, hashMerkleRoot, &daghash.Hash{}, &daghash.Hash{}, dag.genesis.bits, 0),
|
||||
)
|
||||
@@ -1092,8 +1095,8 @@ func TestDAGIndexFailedStatus(t *testing.T) {
|
||||
t.Fatalf("invalidBlockNode status to have %b flags raised (got %b)", statusInvalidAncestor, invalidBlockChildNode.status)
|
||||
}
|
||||
|
||||
invalidMsgBlockGrandChild := appmessage.NewMsgBlock(
|
||||
appmessage.NewBlockHeader(1, []*daghash.Hash{
|
||||
invalidMsgBlockGrandChild := domainmessage.NewMsgBlock(
|
||||
domainmessage.NewBlockHeader(1, []*daghash.Hash{
|
||||
invalidBlockChild.Hash(),
|
||||
}, hashMerkleRoot, &daghash.Hash{}, &daghash.Hash{}, dag.genesis.bits, 0),
|
||||
)
|
||||
@@ -1121,7 +1124,22 @@ func TestDAGIndexFailedStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testProcessBlockRuleError(t *testing.T, dag *BlockDAG, block *appmessage.MsgBlock, expectedRuleErr error) {
|
||||
func TestIsDAGCurrentMaxDiff(t *testing.T) {
|
||||
netParams := []*dagconfig.Params{
|
||||
&dagconfig.MainnetParams,
|
||||
&dagconfig.TestnetParams,
|
||||
&dagconfig.DevnetParams,
|
||||
&dagconfig.RegressionNetParams,
|
||||
&dagconfig.SimnetParams,
|
||||
}
|
||||
for _, params := range netParams {
|
||||
if params.FinalityDuration < isDAGCurrentMaxDiff*params.TargetTimePerBlock {
|
||||
t.Errorf("in %s, a DAG can be considered current even if it's below the finality point", params.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testProcessBlockRuleError(t *testing.T, dag *BlockDAG, block *domainmessage.MsgBlock, expectedRuleErr error) {
|
||||
isOrphan, isDelayed, err := dag.ProcessBlock(util.NewBlock(block), BFNoPoWCheck)
|
||||
|
||||
err = checkRuleError(err, expectedRuleErr)
|
||||
@@ -1157,24 +1175,24 @@ func TestDoubleSpends(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to build signature script: %s", err)
|
||||
}
|
||||
txIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: appmessage.Outpoint{TxID: *cbTx.TxID(), Index: 0},
|
||||
txIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: domainmessage.Outpoint{TxID: *cbTx.TxID(), Index: 0},
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
}
|
||||
txOut := &appmessage.TxOut{
|
||||
txOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: OpTrueScript,
|
||||
Value: uint64(1),
|
||||
}
|
||||
tx1 := appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn}, []*appmessage.TxOut{txOut})
|
||||
tx1 := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn}, []*domainmessage.TxOut{txOut})
|
||||
|
||||
doubleSpendTxOut := &appmessage.TxOut{
|
||||
doubleSpendTxOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: OpTrueScript,
|
||||
Value: uint64(2),
|
||||
}
|
||||
doubleSpendTx1 := appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn}, []*appmessage.TxOut{doubleSpendTxOut})
|
||||
doubleSpendTx1 := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn}, []*domainmessage.TxOut{doubleSpendTxOut})
|
||||
|
||||
blockWithTx1 := PrepareAndProcessBlockForTest(t, dag, []*daghash.Hash{fundingBlock.BlockHash()}, []*appmessage.MsgTx{tx1})
|
||||
blockWithTx1 := PrepareAndProcessBlockForTest(t, dag, []*daghash.Hash{fundingBlock.BlockHash()}, []*domainmessage.MsgTx{tx1})
|
||||
|
||||
// Check that a block will be rejected if it has a transaction that already exists in its past.
|
||||
anotherBlockWithTx1, err := PrepareBlockForTest(dag, []*daghash.Hash{blockWithTx1.BlockHash()}, nil)
|
||||
@@ -1209,7 +1227,7 @@ func TestDoubleSpends(t *testing.T) {
|
||||
|
||||
testProcessBlockRuleError(t, dag, blockWithDoubleSpendForTx1, ruleError(ErrMissingTxOut, ""))
|
||||
|
||||
blockInAnticoneOfBlockWithTx1, err := PrepareBlockForTest(dag, []*daghash.Hash{fundingBlock.BlockHash()}, []*appmessage.MsgTx{doubleSpendTx1})
|
||||
blockInAnticoneOfBlockWithTx1, err := PrepareBlockForTest(dag, []*daghash.Hash{fundingBlock.BlockHash()}, []*domainmessage.MsgTx{doubleSpendTx1})
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -1264,7 +1282,7 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
|
||||
resetExtraNonceForTest()
|
||||
|
||||
createTx := func(txToSpend *appmessage.MsgTx) *appmessage.MsgTx {
|
||||
createTx := func(txToSpend *domainmessage.MsgTx) *domainmessage.MsgTx {
|
||||
scriptPubKey, err := txscript.PayToScriptHashScript(OpTrueScript)
|
||||
if err != nil {
|
||||
t.Fatalf("TestUTXOCommitment: failed to build script pub key: %s", err)
|
||||
@@ -1273,16 +1291,16 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("TestUTXOCommitment: failed to build signature script: %s", err)
|
||||
}
|
||||
txIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: appmessage.Outpoint{TxID: *txToSpend.TxID(), Index: 0},
|
||||
txIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: domainmessage.Outpoint{TxID: *txToSpend.TxID(), Index: 0},
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
}
|
||||
txOut := &appmessage.TxOut{
|
||||
txOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: scriptPubKey,
|
||||
Value: uint64(1),
|
||||
}
|
||||
return appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn}, []*appmessage.TxOut{txOut})
|
||||
return domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn}, []*domainmessage.TxOut{txOut})
|
||||
}
|
||||
|
||||
// Build the following DAG:
|
||||
@@ -1298,12 +1316,12 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
|
||||
// Block C:
|
||||
txSpendBlockACoinbase := createTx(blockA.Transactions[0])
|
||||
blockCTxs := []*appmessage.MsgTx{txSpendBlockACoinbase}
|
||||
blockCTxs := []*domainmessage.MsgTx{txSpendBlockACoinbase}
|
||||
blockC := PrepareAndProcessBlockForTest(t, dag, []*daghash.Hash{blockA.BlockHash()}, blockCTxs)
|
||||
|
||||
// Block D:
|
||||
txSpendTxInBlockC := createTx(txSpendBlockACoinbase)
|
||||
blockDTxs := []*appmessage.MsgTx{txSpendTxInBlockC}
|
||||
blockDTxs := []*domainmessage.MsgTx{txSpendTxInBlockC}
|
||||
blockD := PrepareAndProcessBlockForTest(t, dag, []*daghash.Hash{blockB.BlockHash(), blockC.BlockHash()}, blockDTxs)
|
||||
|
||||
// Get the pastUTXO of blockD
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/binaryserializer"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -49,7 +49,7 @@ func IsNotInDAGErr(err error) bool {
|
||||
// keys will be iterated in an ascending order by the outpoint index.
|
||||
var outpointIndexByteOrder = binary.BigEndian
|
||||
|
||||
func serializeOutpoint(w io.Writer, outpoint *appmessage.Outpoint) error {
|
||||
func serializeOutpoint(w io.Writer, outpoint *domainmessage.Outpoint) error {
|
||||
_, err := w.Write(outpoint.TxID[:])
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -61,10 +61,10 @@ func serializeOutpoint(w io.Writer, outpoint *appmessage.Outpoint) error {
|
||||
var outpointSerializeSize = daghash.TxIDSize + 4
|
||||
|
||||
// deserializeOutpoint decodes an outpoint from the passed serialized byte
|
||||
// slice into a new appmessage.Outpoint using a format that is suitable for long-
|
||||
// slice into a new domainmessage.Outpoint using a format that is suitable for long-
|
||||
// term storage. This format is described in detail above.
|
||||
func deserializeOutpoint(r io.Reader) (*appmessage.Outpoint, error) {
|
||||
outpoint := &appmessage.Outpoint{}
|
||||
func deserializeOutpoint(r io.Reader) (*domainmessage.Outpoint, error) {
|
||||
outpoint := &domainmessage.Outpoint{}
|
||||
_, err := r.Read(outpoint.TxID[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -410,7 +410,7 @@ func (dag *BlockDAG) processUnprocessedBlockNodes(unprocessedBlockNodes []*block
|
||||
func (dag *BlockDAG) deserializeBlockNode(blockRow []byte) (*blockNode, error) {
|
||||
buffer := bytes.NewReader(blockRow)
|
||||
|
||||
var header appmessage.BlockHeader
|
||||
var header domainmessage.BlockHeader
|
||||
err := header.Deserialize(buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -464,7 +464,7 @@ func (dag *BlockDAG) deserializeBlockNode(blockRow []byte) (*blockNode, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bluesCount, err := appmessage.ReadVarInt(buffer)
|
||||
bluesCount, err := domainmessage.ReadVarInt(buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -483,7 +483,7 @@ func (dag *BlockDAG) deserializeBlockNode(blockRow []byte) (*blockNode, error) {
|
||||
}
|
||||
}
|
||||
|
||||
bluesAnticoneSizesLen, err := appmessage.ReadVarInt(buffer)
|
||||
bluesAnticoneSizesLen, err := domainmessage.ReadVarInt(buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -527,7 +527,7 @@ func storeBlock(dbContext *dbaccess.TxContext, block *util.Block) error {
|
||||
}
|
||||
|
||||
func serializeBlockNode(node *blockNode) ([]byte, error) {
|
||||
w := bytes.NewBuffer(make([]byte, 0, appmessage.MaxBlockHeaderPayload+1))
|
||||
w := bytes.NewBuffer(make([]byte, 0, domainmessage.MaxBlockHeaderPayload+1))
|
||||
header := node.Header()
|
||||
err := header.Serialize(w)
|
||||
if err != nil {
|
||||
@@ -554,7 +554,7 @@ func serializeBlockNode(node *blockNode) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = appmessage.WriteVarInt(w, uint64(len(node.blues)))
|
||||
err = domainmessage.WriteVarInt(w, uint64(len(node.blues)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -566,7 +566,7 @@ func serializeBlockNode(node *blockNode) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
err = appmessage.WriteVarInt(w, uint64(len(node.bluesAnticoneSizes)))
|
||||
err = domainmessage.WriteVarInt(w, uint64(len(node.bluesAnticoneSizes)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -662,16 +662,3 @@ func (dag *BlockDAG) BlockHashesFrom(lowHash *daghash.Hash, limit int) ([]*dagha
|
||||
|
||||
return blockHashes, nil
|
||||
}
|
||||
|
||||
func (dag *BlockDAG) fetchBlueBlocks(node *blockNode) ([]*util.Block, error) {
|
||||
blueBlocks := make([]*util.Block, len(node.blues))
|
||||
for i, blueBlockNode := range node.blues {
|
||||
blueBlock, err := dag.fetchBlockByHash(blueBlockNode.hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blueBlocks[i] = blueBlock
|
||||
}
|
||||
return blueBlocks, nil
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// block given its bluest parent.
|
||||
func (dag *BlockDAG) requiredDifficulty(bluestParent *blockNode, newBlockTime mstime.Time) uint32 {
|
||||
// Genesis block.
|
||||
if dag.Params.DisableDifficultyAdjustment || bluestParent == nil || bluestParent.blueScore < dag.difficultyAdjustmentWindowSize+1 {
|
||||
if bluestParent == nil || bluestParent.blueScore < dag.difficultyAdjustmentWindowSize+1 {
|
||||
return dag.powMaxBits
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"math/big"
|
||||
"testing"
|
||||
@@ -80,7 +80,7 @@ func TestCalcWork(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDifficulty(t *testing.T) {
|
||||
params := dagconfig.MainnetParams
|
||||
params := dagconfig.SimnetParams
|
||||
params.K = 1
|
||||
params.DifficultyAdjustmentWindowSize = 264
|
||||
dag, teardownFunc, err := DAGSetup("TestDifficulty", true, Config{
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/testtools"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domain/mining"
|
||||
"github.com/kaspanet/kaspad/domain/txscript"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/mining"
|
||||
"github.com/kaspanet/kaspad/txscript"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
@@ -125,7 +125,7 @@ func TestFinality(t *testing.T) {
|
||||
t.Errorf("NextBlockCoinbaseTransaction: %s", err)
|
||||
}
|
||||
merkleRoot := blockdag.BuildHashMerkleTreeStore([]*util.Tx{fakeCoinbaseTx}).Root()
|
||||
beforeFinalityBlock := appmessage.NewMsgBlock(&appmessage.BlockHeader{
|
||||
beforeFinalityBlock := domainmessage.NewMsgBlock(&domainmessage.BlockHeader{
|
||||
Version: 0x10000000,
|
||||
ParentHashes: []*daghash.Hash{genesis.Hash()},
|
||||
HashMerkleRoot: merkleRoot,
|
||||
@@ -164,7 +164,7 @@ func TestFinality(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestFinalityInterval tests that the finality interval is
|
||||
// smaller then appmessage.MaxInvPerMsg, so when a peer receives
|
||||
// smaller then domainmessage.MaxInvPerMsg, so when a peer receives
|
||||
// a getblocks message it should always be able to send
|
||||
// all the necessary invs.
|
||||
func TestFinalityInterval(t *testing.T) {
|
||||
@@ -172,6 +172,7 @@ func TestFinalityInterval(t *testing.T) {
|
||||
&dagconfig.MainnetParams,
|
||||
&dagconfig.TestnetParams,
|
||||
&dagconfig.DevnetParams,
|
||||
&dagconfig.RegressionNetParams,
|
||||
&dagconfig.SimnetParams,
|
||||
}
|
||||
for _, params := range netParams {
|
||||
@@ -184,8 +185,8 @@ func TestFinalityInterval(t *testing.T) {
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
if dag.FinalityInterval() > appmessage.MaxInvPerMsg {
|
||||
t.Errorf("FinalityInterval in %s should be lower or equal to appmessage.MaxInvPerMsg", params.Name)
|
||||
if dag.FinalityInterval() > domainmessage.MaxInvPerMsg {
|
||||
t.Errorf("FinalityInterval in %s should be lower or equal to domainmessage.MaxInvPerMsg", params.Name)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -252,34 +253,34 @@ func TestChainedTransactions(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to build signature script: %s", err)
|
||||
}
|
||||
txIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: appmessage.Outpoint{TxID: *cbTx.TxID(), Index: 0},
|
||||
txIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: domainmessage.Outpoint{TxID: *cbTx.TxID(), Index: 0},
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
}
|
||||
txOut := &appmessage.TxOut{
|
||||
txOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: blockdag.OpTrueScript,
|
||||
Value: uint64(1),
|
||||
}
|
||||
tx := appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn}, []*appmessage.TxOut{txOut})
|
||||
tx := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn}, []*domainmessage.TxOut{txOut})
|
||||
|
||||
chainedTxIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: appmessage.Outpoint{TxID: *tx.TxID(), Index: 0},
|
||||
chainedTxIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: domainmessage.Outpoint{TxID: *tx.TxID(), Index: 0},
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
}
|
||||
|
||||
scriptPubKey, err := txscript.PayToScriptHashScript(blockdag.OpTrueScript)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to build public key script: %s", err)
|
||||
}
|
||||
chainedTxOut := &appmessage.TxOut{
|
||||
chainedTxOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: scriptPubKey,
|
||||
Value: uint64(1),
|
||||
}
|
||||
chainedTx := appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{chainedTxIn}, []*appmessage.TxOut{chainedTxOut})
|
||||
chainedTx := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{chainedTxIn}, []*domainmessage.TxOut{chainedTxOut})
|
||||
|
||||
block2, err := mining.PrepareBlockForTest(dag, []*daghash.Hash{block1.BlockHash()}, []*appmessage.MsgTx{tx}, false)
|
||||
block2, err := mining.PrepareBlockForTest(dag, []*daghash.Hash{block1.BlockHash()}, []*domainmessage.MsgTx{tx}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -314,18 +315,18 @@ func TestChainedTransactions(t *testing.T) {
|
||||
t.Errorf("ProcessBlock: block2 got unexpectedly orphaned")
|
||||
}
|
||||
|
||||
nonChainedTxIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: appmessage.Outpoint{TxID: *cbTx.TxID(), Index: 0},
|
||||
nonChainedTxIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: domainmessage.Outpoint{TxID: *cbTx.TxID(), Index: 0},
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
}
|
||||
nonChainedTxOut := &appmessage.TxOut{
|
||||
nonChainedTxOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: scriptPubKey,
|
||||
Value: uint64(1),
|
||||
}
|
||||
nonChainedTx := appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{nonChainedTxIn}, []*appmessage.TxOut{nonChainedTxOut})
|
||||
nonChainedTx := domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{nonChainedTxIn}, []*domainmessage.TxOut{nonChainedTxOut})
|
||||
|
||||
block3, err := mining.PrepareBlockForTest(dag, []*daghash.Hash{block1.BlockHash()}, []*appmessage.MsgTx{nonChainedTx}, false)
|
||||
block3, err := mining.PrepareBlockForTest(dag, []*daghash.Hash{block1.BlockHash()}, []*domainmessage.MsgTx{nonChainedTx}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -362,23 +363,23 @@ func TestOrderInDiffFromAcceptanceData(t *testing.T) {
|
||||
|
||||
createBlock := func(previousBlock *util.Block) *util.Block {
|
||||
// Prepare a transaction that spends the previous block's coinbase transaction
|
||||
var txs []*appmessage.MsgTx
|
||||
var txs []*domainmessage.MsgTx
|
||||
if !previousBlock.IsGenesis() {
|
||||
previousCoinbaseTx := previousBlock.MsgBlock().Transactions[0]
|
||||
signatureScript, err := txscript.PayToScriptHashSignatureScript(blockdag.OpTrueScript, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("TestOrderInDiffFromAcceptanceData: Failed to build signature script: %s", err)
|
||||
}
|
||||
txIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: appmessage.Outpoint{TxID: *previousCoinbaseTx.TxID(), Index: 0},
|
||||
txIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: domainmessage.Outpoint{TxID: *previousCoinbaseTx.TxID(), Index: 0},
|
||||
SignatureScript: signatureScript,
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
}
|
||||
txOut := &appmessage.TxOut{
|
||||
txOut := &domainmessage.TxOut{
|
||||
ScriptPubKey: blockdag.OpTrueScript,
|
||||
Value: uint64(1),
|
||||
}
|
||||
txs = append(txs, appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn}, []*appmessage.TxOut{txOut}))
|
||||
txs = append(txs, domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn}, []*domainmessage.TxOut{txOut}))
|
||||
}
|
||||
|
||||
// Create the block
|
||||
@@ -437,7 +438,7 @@ func TestGasLimit(t *testing.T) {
|
||||
t.Fatalf("could not register network: %s", err)
|
||||
}
|
||||
|
||||
cbTxs := []*appmessage.MsgTx{}
|
||||
cbTxs := []*domainmessage.MsgTx{}
|
||||
for i := 0; i < 4; i++ {
|
||||
fundsBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), nil, false)
|
||||
if err != nil {
|
||||
@@ -468,30 +469,30 @@ func TestGasLimit(t *testing.T) {
|
||||
t.Fatalf("Failed to build public key script: %s", err)
|
||||
}
|
||||
|
||||
tx1In := &appmessage.TxIn{
|
||||
PreviousOutpoint: *appmessage.NewOutpoint(cbTxs[0].TxID(), 0),
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
tx1In := &domainmessage.TxIn{
|
||||
PreviousOutpoint: *domainmessage.NewOutpoint(cbTxs[0].TxID(), 0),
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
SignatureScript: signatureScript,
|
||||
}
|
||||
tx1Out := &appmessage.TxOut{
|
||||
tx1Out := &domainmessage.TxOut{
|
||||
Value: cbTxs[0].TxOut[0].Value,
|
||||
ScriptPubKey: scriptPubKey,
|
||||
}
|
||||
tx1 := appmessage.NewSubnetworkMsgTx(appmessage.TxVersion, []*appmessage.TxIn{tx1In}, []*appmessage.TxOut{tx1Out}, subnetworkID, 10000, []byte{})
|
||||
tx1 := domainmessage.NewSubnetworkMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{tx1In}, []*domainmessage.TxOut{tx1Out}, subnetworkID, 10000, []byte{})
|
||||
|
||||
tx2In := &appmessage.TxIn{
|
||||
PreviousOutpoint: *appmessage.NewOutpoint(cbTxs[1].TxID(), 0),
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
tx2In := &domainmessage.TxIn{
|
||||
PreviousOutpoint: *domainmessage.NewOutpoint(cbTxs[1].TxID(), 0),
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
SignatureScript: signatureScript,
|
||||
}
|
||||
tx2Out := &appmessage.TxOut{
|
||||
tx2Out := &domainmessage.TxOut{
|
||||
Value: cbTxs[1].TxOut[0].Value,
|
||||
ScriptPubKey: scriptPubKey,
|
||||
}
|
||||
tx2 := appmessage.NewSubnetworkMsgTx(appmessage.TxVersion, []*appmessage.TxIn{tx2In}, []*appmessage.TxOut{tx2Out}, subnetworkID, 10000, []byte{})
|
||||
tx2 := domainmessage.NewSubnetworkMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{tx2In}, []*domainmessage.TxOut{tx2Out}, subnetworkID, 10000, []byte{})
|
||||
|
||||
// Here we check that we can't process a block that has transactions that exceed the gas limit
|
||||
overLimitBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*appmessage.MsgTx{tx1, tx2}, true)
|
||||
overLimitBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*domainmessage.MsgTx{tx1, tx2}, true)
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -513,20 +514,20 @@ func TestGasLimit(t *testing.T) {
|
||||
t.Fatalf("ProcessBlock: overLimitBlock got unexpectedly orphan")
|
||||
}
|
||||
|
||||
overflowGasTxIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: *appmessage.NewOutpoint(cbTxs[2].TxID(), 0),
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
overflowGasTxIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: *domainmessage.NewOutpoint(cbTxs[2].TxID(), 0),
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
SignatureScript: signatureScript,
|
||||
}
|
||||
overflowGasTxOut := &appmessage.TxOut{
|
||||
overflowGasTxOut := &domainmessage.TxOut{
|
||||
Value: cbTxs[2].TxOut[0].Value,
|
||||
ScriptPubKey: scriptPubKey,
|
||||
}
|
||||
overflowGasTx := appmessage.NewSubnetworkMsgTx(appmessage.TxVersion, []*appmessage.TxIn{overflowGasTxIn}, []*appmessage.TxOut{overflowGasTxOut},
|
||||
overflowGasTx := domainmessage.NewSubnetworkMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{overflowGasTxIn}, []*domainmessage.TxOut{overflowGasTxOut},
|
||||
subnetworkID, math.MaxUint64, []byte{})
|
||||
|
||||
// Here we check that we can't process a block that its transactions' gas overflows uint64
|
||||
overflowGasBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*appmessage.MsgTx{tx1, overflowGasTx}, true)
|
||||
overflowGasBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*domainmessage.MsgTx{tx1, overflowGasTx}, true)
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -548,19 +549,19 @@ func TestGasLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
nonExistentSubnetwork := &subnetworkid.SubnetworkID{123}
|
||||
nonExistentSubnetworkTxIn := &appmessage.TxIn{
|
||||
PreviousOutpoint: *appmessage.NewOutpoint(cbTxs[3].TxID(), 0),
|
||||
Sequence: appmessage.MaxTxInSequenceNum,
|
||||
nonExistentSubnetworkTxIn := &domainmessage.TxIn{
|
||||
PreviousOutpoint: *domainmessage.NewOutpoint(cbTxs[3].TxID(), 0),
|
||||
Sequence: domainmessage.MaxTxInSequenceNum,
|
||||
SignatureScript: signatureScript,
|
||||
}
|
||||
nonExistentSubnetworkTxOut := &appmessage.TxOut{
|
||||
nonExistentSubnetworkTxOut := &domainmessage.TxOut{
|
||||
Value: cbTxs[3].TxOut[0].Value,
|
||||
ScriptPubKey: scriptPubKey,
|
||||
}
|
||||
nonExistentSubnetworkTx := appmessage.NewSubnetworkMsgTx(appmessage.TxVersion, []*appmessage.TxIn{nonExistentSubnetworkTxIn},
|
||||
[]*appmessage.TxOut{nonExistentSubnetworkTxOut}, nonExistentSubnetwork, 1, []byte{})
|
||||
nonExistentSubnetworkTx := domainmessage.NewSubnetworkMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{nonExistentSubnetworkTxIn},
|
||||
[]*domainmessage.TxOut{nonExistentSubnetworkTxOut}, nonExistentSubnetwork, 1, []byte{})
|
||||
|
||||
nonExistentSubnetworkBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*appmessage.MsgTx{nonExistentSubnetworkTx, overflowGasTx}, true)
|
||||
nonExistentSubnetworkBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*domainmessage.MsgTx{nonExistentSubnetworkTx, overflowGasTx}, true)
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -581,7 +582,7 @@ func TestGasLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
// Here we check that we can process a block with a transaction that doesn't exceed the gas limit
|
||||
validBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*appmessage.MsgTx{tx1}, true)
|
||||
validBlock, err := mining.PrepareBlockForTest(dag, dag.TipHashes(), []*domainmessage.MsgTx{tx1}, true)
|
||||
if err != nil {
|
||||
t.Fatalf("PrepareBlockForTest: %v", err)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
"sort"
|
||||
)
|
||||
@@ -1,34 +1,24 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
type block struct {
|
||||
ID string // id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash
|
||||
ExpectedScore uint64
|
||||
ExpectedSelectedParent string
|
||||
ExpectedBlues []string
|
||||
Parents []string
|
||||
}
|
||||
|
||||
type testData struct {
|
||||
K dagconfig.KType
|
||||
GenesisID string
|
||||
ExpectedReds []string
|
||||
Blocks []block
|
||||
type testBlockData struct {
|
||||
parents []string
|
||||
id string // id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash
|
||||
expectedScore uint64
|
||||
expectedSelectedParent string
|
||||
expectedBlues []string
|
||||
}
|
||||
|
||||
// TestGHOSTDAG iterates over several dag simulations, and checks
|
||||
@@ -36,26 +26,158 @@ type testData struct {
|
||||
// block are calculated as expected.
|
||||
func TestGHOSTDAG(t *testing.T) {
|
||||
dagParams := dagconfig.SimnetParams
|
||||
err := filepath.Walk("./testdata/dags/", func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
var test testData
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("TestGHOSTDAG: failed opening file: %s", path)
|
||||
}
|
||||
decoder := json.NewDecoder(file)
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&test)
|
||||
if err != nil {
|
||||
t.Fatalf("TestGHOSTDAG: test: %s, failed decoding json: %v", info.Name(), err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
k dagconfig.KType
|
||||
expectedReds []string
|
||||
dagData []*testBlockData
|
||||
}{
|
||||
{
|
||||
k: 3,
|
||||
expectedReds: []string{"F", "G", "H", "I", "N", "P"},
|
||||
dagData: []*testBlockData{
|
||||
{
|
||||
parents: []string{"A"},
|
||||
id: "B",
|
||||
expectedScore: 1,
|
||||
expectedSelectedParent: "A",
|
||||
expectedBlues: []string{"A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"B"},
|
||||
id: "C",
|
||||
expectedScore: 2,
|
||||
expectedSelectedParent: "B",
|
||||
expectedBlues: []string{"B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"A"},
|
||||
id: "D",
|
||||
expectedScore: 1,
|
||||
expectedSelectedParent: "A",
|
||||
expectedBlues: []string{"A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"C", "D"},
|
||||
id: "E",
|
||||
expectedScore: 4,
|
||||
expectedSelectedParent: "C",
|
||||
expectedBlues: []string{"C", "D"},
|
||||
},
|
||||
{
|
||||
parents: []string{"A"},
|
||||
id: "F",
|
||||
expectedScore: 1,
|
||||
expectedSelectedParent: "A",
|
||||
expectedBlues: []string{"A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"F"},
|
||||
id: "G",
|
||||
expectedScore: 2,
|
||||
expectedSelectedParent: "F",
|
||||
expectedBlues: []string{"F"},
|
||||
},
|
||||
{
|
||||
parents: []string{"A"},
|
||||
id: "H",
|
||||
expectedScore: 1,
|
||||
expectedSelectedParent: "A",
|
||||
expectedBlues: []string{"A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"A"},
|
||||
id: "I",
|
||||
expectedScore: 1,
|
||||
expectedSelectedParent: "A",
|
||||
expectedBlues: []string{"A"},
|
||||
},
|
||||
{
|
||||
parents: []string{"E", "G"},
|
||||
id: "J",
|
||||
expectedScore: 5,
|
||||
expectedSelectedParent: "E",
|
||||
expectedBlues: []string{"E"},
|
||||
},
|
||||
{
|
||||
parents: []string{"J"},
|
||||
id: "K",
|
||||
expectedScore: 6,
|
||||
expectedSelectedParent: "J",
|
||||
expectedBlues: []string{"J"},
|
||||
},
|
||||
{
|
||||
parents: []string{"I", "K"},
|
||||
id: "L",
|
||||
expectedScore: 7,
|
||||
expectedSelectedParent: "K",
|
||||
expectedBlues: []string{"K"},
|
||||
},
|
||||
{
|
||||
parents: []string{"L"},
|
||||
id: "M",
|
||||
expectedScore: 8,
|
||||
expectedSelectedParent: "L",
|
||||
expectedBlues: []string{"L"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "N",
|
||||
expectedScore: 9,
|
||||
expectedSelectedParent: "M",
|
||||
expectedBlues: []string{"M"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "O",
|
||||
expectedScore: 9,
|
||||
expectedSelectedParent: "M",
|
||||
expectedBlues: []string{"M"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "P",
|
||||
expectedScore: 9,
|
||||
expectedSelectedParent: "M",
|
||||
expectedBlues: []string{"M"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "Q",
|
||||
expectedScore: 9,
|
||||
expectedSelectedParent: "M",
|
||||
expectedBlues: []string{"M"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "R",
|
||||
expectedScore: 9,
|
||||
expectedSelectedParent: "M",
|
||||
expectedBlues: []string{"M"},
|
||||
},
|
||||
{
|
||||
parents: []string{"R"},
|
||||
id: "S",
|
||||
expectedScore: 10,
|
||||
expectedSelectedParent: "R",
|
||||
expectedBlues: []string{"R"},
|
||||
},
|
||||
{
|
||||
parents: []string{"N", "O", "P", "Q", "S"},
|
||||
id: "T",
|
||||
expectedScore: 13,
|
||||
expectedSelectedParent: "S",
|
||||
expectedBlues: []string{"S", "O", "Q"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
func() {
|
||||
resetExtraNonceForTest()
|
||||
dagParams.K = test.K
|
||||
dag, teardownFunc, err := DAGSetup(fmt.Sprintf("TestGHOSTDAG %s", info.Name()), true, Config{
|
||||
dagParams.K = test.k
|
||||
dag, teardownFunc, err := DAGSetup(fmt.Sprintf("TestGHOSTDAG%d", i), true, Config{
|
||||
DAGParams: &dagParams,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -66,33 +188,32 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
genesisNode := dag.genesis
|
||||
blockByIDMap := make(map[string]*blockNode)
|
||||
idByBlockMap := make(map[*blockNode]string)
|
||||
blockByIDMap[test.GenesisID] = genesisNode
|
||||
idByBlockMap[genesisNode] = test.GenesisID
|
||||
blockByIDMap["A"] = genesisNode
|
||||
idByBlockMap[genesisNode] = "A"
|
||||
|
||||
for _, blockData := range test.Blocks {
|
||||
for _, blockData := range test.dagData {
|
||||
parents := blockSet{}
|
||||
for _, parentID := range blockData.Parents {
|
||||
for _, parentID := range blockData.parents {
|
||||
parent := blockByIDMap[parentID]
|
||||
parents.add(parent)
|
||||
}
|
||||
|
||||
block, err := PrepareBlockForTest(dag, parents.hashes(), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("TestGHOSTDAG: block %s got unexpected error from PrepareBlockForTest: %v", blockData.ID,
|
||||
err)
|
||||
t.Fatalf("TestGHOSTDAG: block %v got unexpected error from PrepareBlockForTest: %v", blockData.id, err)
|
||||
}
|
||||
|
||||
utilBlock := util.NewBlock(block)
|
||||
isOrphan, isDelayed, err := dag.ProcessBlock(utilBlock, BFNoPoWCheck)
|
||||
if err != nil {
|
||||
t.Fatalf("TestGHOSTDAG: dag.ProcessBlock got unexpected error for block %s: %v", blockData.ID, err)
|
||||
t.Fatalf("TestGHOSTDAG: dag.ProcessBlock got unexpected error for block %v: %v", blockData.id, err)
|
||||
}
|
||||
if isDelayed {
|
||||
t.Fatalf("TestGHOSTDAG: block %s "+
|
||||
"is too far in the future", blockData.ID)
|
||||
"is too far in the future", blockData.id)
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("TestGHOSTDAG: block %s was unexpectedly orphan", blockData.ID)
|
||||
t.Fatalf("TestGHOSTDAG: block %v was unexpectedly orphan", blockData.id)
|
||||
}
|
||||
|
||||
node, ok := dag.index.LookupNode(utilBlock.Hash())
|
||||
@@ -100,8 +221,8 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
t.Fatalf("block %s does not exist in the DAG", utilBlock.Hash())
|
||||
}
|
||||
|
||||
blockByIDMap[blockData.ID] = node
|
||||
idByBlockMap[node] = blockData.ID
|
||||
blockByIDMap[blockData.id] = node
|
||||
idByBlockMap[node] = blockData.id
|
||||
|
||||
bluesIDs := make([]string, 0, len(node.blues))
|
||||
for _, blue := range node.blues {
|
||||
@@ -110,17 +231,17 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
selectedParentID := idByBlockMap[node.selectedParent]
|
||||
fullDataStr := fmt.Sprintf("blues: %v, selectedParent: %v, score: %v",
|
||||
bluesIDs, selectedParentID, node.blueScore)
|
||||
if blockData.ExpectedScore != node.blueScore {
|
||||
t.Errorf("Test %s: Block %s expected to have score %v but got %v (fulldata: %v)",
|
||||
info.Name(), blockData.ID, blockData.ExpectedScore, node.blueScore, fullDataStr)
|
||||
if blockData.expectedScore != node.blueScore {
|
||||
t.Errorf("Test %d: Block %v expected to have score %v but got %v (fulldata: %v)",
|
||||
i, blockData.id, blockData.expectedScore, node.blueScore, fullDataStr)
|
||||
}
|
||||
if blockData.ExpectedSelectedParent != selectedParentID {
|
||||
t.Errorf("Test %s: Block %s expected to have selected parent %v but got %v (fulldata: %v)",
|
||||
info.Name(), blockData.ID, blockData.ExpectedSelectedParent, selectedParentID, fullDataStr)
|
||||
if blockData.expectedSelectedParent != selectedParentID {
|
||||
t.Errorf("Test %d: Block %v expected to have selected parent %v but got %v (fulldata: %v)",
|
||||
i, blockData.id, blockData.expectedSelectedParent, selectedParentID, fullDataStr)
|
||||
}
|
||||
if !reflect.DeepEqual(blockData.ExpectedBlues, bluesIDs) {
|
||||
t.Errorf("Test %s: Block %s expected to have blues %v but got %v (fulldata: %v)",
|
||||
info.Name(), blockData.ID, blockData.ExpectedBlues, bluesIDs, fullDataStr)
|
||||
if !reflect.DeepEqual(blockData.expectedBlues, bluesIDs) {
|
||||
t.Errorf("Test %d: Block %v expected to have blues %v but got %v (fulldata: %v)",
|
||||
i, blockData.id, blockData.expectedBlues, bluesIDs, fullDataStr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,22 +259,16 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
delete(reds, blueID)
|
||||
}
|
||||
}
|
||||
if !checkReds(test.ExpectedReds, reds) {
|
||||
if !checkReds(test.expectedReds, reds) {
|
||||
redsIDs := make([]string, 0, len(reds))
|
||||
for id := range reds {
|
||||
redsIDs = append(redsIDs, id)
|
||||
}
|
||||
sort.Strings(redsIDs)
|
||||
sort.Strings(test.ExpectedReds)
|
||||
t.Errorf("Test %s: Expected reds %v but got %v", info.Name(), test.ExpectedReds, redsIDs)
|
||||
sort.Strings(test.expectedReds)
|
||||
t.Errorf("Test %d: Expected reds %v but got %v", i, test.expectedReds, redsIDs)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
@@ -113,7 +113,7 @@ func (idx *AcceptanceIndex) TxsAcceptanceData(blockHash *daghash.Hash) (blockdag
|
||||
}
|
||||
|
||||
type serializableTxAcceptanceData struct {
|
||||
MsgTx appmessage.MsgTx
|
||||
MsgTx domainmessage.MsgTx
|
||||
IsAccepted bool
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/domainmessage"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/pkg/errors"
|
||||
@@ -21,19 +21,19 @@ import (
|
||||
func TestAcceptanceIndexSerializationAndDeserialization(t *testing.T) {
|
||||
// Create test data
|
||||
hash, _ := daghash.NewHashFromStr("1111111111111111111111111111111111111111111111111111111111111111")
|
||||
txIn1 := &appmessage.TxIn{SignatureScript: []byte{1}, PreviousOutpoint: appmessage.Outpoint{Index: 1}, Sequence: 0}
|
||||
txIn2 := &appmessage.TxIn{SignatureScript: []byte{2}, PreviousOutpoint: appmessage.Outpoint{Index: 2}, Sequence: 0}
|
||||
txOut1 := &appmessage.TxOut{ScriptPubKey: []byte{1}, Value: 10}
|
||||
txOut2 := &appmessage.TxOut{ScriptPubKey: []byte{2}, Value: 20}
|
||||
txIn1 := &domainmessage.TxIn{SignatureScript: []byte{1}, PreviousOutpoint: domainmessage.Outpoint{Index: 1}, Sequence: 0}
|
||||
txIn2 := &domainmessage.TxIn{SignatureScript: []byte{2}, PreviousOutpoint: domainmessage.Outpoint{Index: 2}, Sequence: 0}
|
||||
txOut1 := &domainmessage.TxOut{ScriptPubKey: []byte{1}, Value: 10}
|
||||
txOut2 := &domainmessage.TxOut{ScriptPubKey: []byte{2}, Value: 20}
|
||||
blockTxsAcceptanceData := blockdag.BlockTxsAcceptanceData{
|
||||
BlockHash: *hash,
|
||||
TxAcceptanceData: []blockdag.TxAcceptanceData{
|
||||
{
|
||||
Tx: util.NewTx(appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn1}, []*appmessage.TxOut{txOut1})),
|
||||
Tx: util.NewTx(domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn1}, []*domainmessage.TxOut{txOut1})),
|
||||
IsAccepted: true,
|
||||
},
|
||||
{
|
||||
Tx: util.NewTx(appmessage.NewNativeMsgTx(appmessage.TxVersion, []*appmessage.TxIn{txIn2}, []*appmessage.TxOut{txOut2})),
|
||||
Tx: util.NewTx(domainmessage.NewNativeMsgTx(domainmessage.TxVersion, []*domainmessage.TxIn{txIn2}, []*domainmessage.TxOut{txOut2})),
|
||||
IsAccepted: false,
|
||||
},
|
||||
},
|
||||
@@ -8,8 +8,8 @@ Package indexers implements optional block DAG indexes.
|
||||
package indexers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package indexers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.INDX)
|
||||
@@ -5,8 +5,8 @@
|
||||
package indexers
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user