Cleaning up in preparation to set up peer info ads
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,3 +20,4 @@ vendor/
|
||||
/.idea/indra.iml
|
||||
/.idea/codeStyles/codeStyleConfig.xml
|
||||
/.idea/**
|
||||
/localversion.go
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="go test git-indra.lan/indra-labs/indra/pkg" type="GoTestRunConfiguration" factoryName="Go Test" singleton="false">
|
||||
<module name="indra" />
|
||||
<working_directory value="$PROJECT_DIR$/pkg" />
|
||||
<go_parameters value="-v ./..." />
|
||||
<go_parameters value="-v ./... -tags local" />
|
||||
<root_directory value="$PROJECT_DIR$" />
|
||||
<kind value="DIRECTORY" />
|
||||
<package value="git-indra.lan/indra-labs/indra/pkg/engine" />
|
||||
|
||||
@@ -181,8 +181,14 @@ func main() {
|
||||
if dir, e = os.Getwd(); check(e) {
|
||||
}
|
||||
name := filepath.Base(dir)
|
||||
versionFile := `package ` + name + `
|
||||
versionFile := `//go:build !local
|
||||
|
||||
// This can be overridden by a developer's version by setting the tag local
|
||||
// on a modified version. This is useful for the code locations in teh logs.
|
||||
|
||||
package ` + name + `
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Put invocations to run all the generators in here (
|
||||
// check cmd/bumper/ to add them, and they will automatically run with:
|
||||
@@ -190,7 +196,6 @@ func main() {
|
||||
// $ go generate .
|
||||
//
|
||||
// which will run all these generators below and finish with a go install.
|
||||
` + `//go:generate go run ./pkg/relay/gen/main.go
|
||||
` + `//go:generate go install ./...
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
package advert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/indra-labs/indra"
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"net/netip"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
AddressLen = nonce.IDLen +
|
||||
splice.AddrLen + 1 +
|
||||
slice.Uint64Len +
|
||||
crypto.SigLen
|
||||
PeerLen = magic.Len +
|
||||
nonce.IDLen +
|
||||
slice.Uint64Len +
|
||||
crypto.SigLen
|
||||
ServiceLen = nonce.IDLen +
|
||||
2*slice.Uint16Len +
|
||||
slice.Uint32Len +
|
||||
crypto.SigLen
|
||||
)
|
||||
|
||||
var (
|
||||
log = log2.GetLogger(indra.PathBase)
|
||||
fails = log.E.Chk
|
||||
)
|
||||
|
||||
// Address entries are stored with an index generated by concatenating the bytes
|
||||
// of the public key with a string path "/address/N" where N is the index of the
|
||||
// address. This means hidden service introducers for values over zero.
|
||||
// Hidden services have no value in the zero index, which is "<hash>/address/0".
|
||||
type Address struct {
|
||||
ID nonce.ID // To ensure no repeating message
|
||||
Multiaddr multiaddr.Multiaddr // We only use a netip.AddrPort though.
|
||||
Index byte // This is the index in the slice from Peer.
|
||||
Expiry time.Time // zero for relay's public address (32 bit).
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func (a *Address) Decode(s *splice.Splice) (e error) {
|
||||
var addr *netip.AddrPort
|
||||
s.ReadID(&a.ID).ReadAddrPort(&addr).ReadByte(&a.Index).ReadTime(&a.Expiry)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Address) Encode(s *splice.Splice) (e error) {
|
||||
var ip, port string
|
||||
if ip, e = a.Multiaddr.ValueForProtocol(multiaddr.P_IP4); fails(e) {
|
||||
}
|
||||
if ip == "" {
|
||||
if ip, e = a.Multiaddr.ValueForProtocol(multiaddr.P_IP6); fails(e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if port, e = a.Multiaddr.ValueForProtocol(multiaddr.P_TCP); fails(e) {
|
||||
return
|
||||
}
|
||||
var addr netip.AddrPort
|
||||
if addr, e = netip.ParseAddrPort(ip + ":" + port); fails(e) {
|
||||
}
|
||||
s.ID(a.ID).AddrPort(&addr).Byte(a.Index).Time(a.Expiry)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Address) GetOnion() interface{} { return nil }
|
||||
|
||||
func (a *Address) Len() int { return AddressLen }
|
||||
|
||||
func (a *Address) Magic() string { return "" }
|
||||
|
||||
func (a *Address) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(a.Len())
|
||||
if e = a.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(a.Sig[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Address) Validate(s *splice.Splice) (pub *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+splice.AddrLen+1+
|
||||
slice.Uint64Len))
|
||||
var e error
|
||||
if pub, e = a.Sig.Recover(h); fails(e) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Peer is the root identity document for an Indra peer. It is indexed by the
|
||||
// Identity field, its public key. The slices found below it are derived via
|
||||
// concatenation of strings with the keys and hashing to generate a derived
|
||||
// field index, used to search the DHT for matches.
|
||||
//
|
||||
// The data stored for Peer must be signed with the key claimed by the Identity.
|
||||
// For hidden services the address fields are signed in the DHT by the hidden
|
||||
// service from their introduction solicitation, and the index from the current
|
||||
// set is given by the hidden service.
|
||||
type Peer struct {
|
||||
nonce.ID // To ensure no repeating message
|
||||
Identity crypto.PubBytes
|
||||
RelayRate int
|
||||
Sig crypto.SigBytes
|
||||
// Addresses - first is address, nil for hidden services,
|
||||
// hidden services have more than one, 6 or more are kept active.
|
||||
Addresses []*Address
|
||||
Services []Service
|
||||
}
|
||||
|
||||
func (p *Peer) Decode(s *splice.Splice) (e error) {
|
||||
var v uint64
|
||||
s.ReadID(&p.ID).ReadUint64(&v)
|
||||
s.ReadSignature(&p.Sig)
|
||||
p.RelayRate = int(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Peer) Encode(s *splice.Splice) (e error) {
|
||||
s.ID(p.ID).Uint64(uint64(p.RelayRate))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Peer) GetOnion() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Peer) Len() int {
|
||||
return PeerLen
|
||||
}
|
||||
|
||||
func (p *Peer) Magic() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Peer) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(p.Len())
|
||||
if e = p.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(p.Sig[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Peer) Validate(s *splice.Splice) (pk *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+slice.Uint64Len))
|
||||
var e error
|
||||
if pk, e = p.Sig.Recover(h); fails(e) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Service stores a specification for the fee rate and the service port, which
|
||||
// must be a well known port to match with a type of service, eg 80 for web, 53
|
||||
// for DNS, etc. These are also attached to the Peer entry via concatenating
|
||||
// "/service/N" where N is the index of the entry. A zero value at an index
|
||||
// signals to stop scanning for more subsequent values.
|
||||
type Service struct {
|
||||
ID nonce.ID // To ensure no repeating message
|
||||
Index uint16 // This is the index in the slice from Peer.
|
||||
Port uint16
|
||||
RelayRate uint32
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func (sv *Service) Decode(s *splice.Splice) (e error) {
|
||||
s.ReadID(&sv.ID).
|
||||
ReadUint16(&sv.Index).
|
||||
ReadUint16(&sv.Port).
|
||||
ReadUint32(&sv.RelayRate)
|
||||
return
|
||||
}
|
||||
|
||||
func (sv *Service) Encode(s *splice.Splice) (e error) {
|
||||
s.ID(sv.ID).Uint16(sv.Index).Uint16(sv.Port).Uint32(sv.RelayRate)
|
||||
return
|
||||
}
|
||||
|
||||
func (sv *Service) GetOnion() interface{} { return nil }
|
||||
|
||||
func (sv *Service) Len() int { return ServiceLen }
|
||||
|
||||
func (sv *Service) Magic() string { return "" }
|
||||
|
||||
func (sv *Service) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(sv.Len())
|
||||
if e = sv.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(sv.Sig[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sv *Service) Validate(s *splice.Splice) (pub *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+2*slice.Uint16Len+
|
||||
slice.Uint64Len))
|
||||
var e error
|
||||
if pub, e = sv.Sig.Recover(h); fails(e) {
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package dispatcher
|
||||
import (
|
||||
"context"
|
||||
"github.com/indra-labs/indra/pkg/engine"
|
||||
"github.com/indra-labs/indra/pkg/engine/onions"
|
||||
"github.com/indra-labs/indra/pkg/engine/services"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/cryptorand"
|
||||
@@ -14,7 +15,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/engine/onions"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestDispatcher(t *testing.T) {
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
l1, e = transport.NewListener("", transport.LocalhostZeroIPv4QUIC,
|
||||
l1, e = transport.NewListener("", transport.LocalhostZeroIPv4TCP,
|
||||
dataPath, k1, ctx, transport.DefaultMTU)
|
||||
if fails(e) {
|
||||
t.FailNow()
|
||||
@@ -51,7 +51,7 @@ func TestDispatcher(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
l2, e = transport.NewListener(transport.GetHostAddress(l1.Host),
|
||||
transport.LocalhostZeroIPv4QUIC, dataPath, k2, ctx, transport.DefaultMTU)
|
||||
transport.LocalhostZeroIPv4TCP, dataPath, k2, ctx, transport.DefaultMTU)
|
||||
if fails(e) {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func TestEngine_SendHiddenService(t *testing.T) {
|
||||
// index of introducerHops will be a randomly selected one.
|
||||
introducer = introducerHops[0]
|
||||
returner = returnHops[0]
|
||||
wg.Add(1)
|
||||
//wg.Add(1)
|
||||
counter.Inc()
|
||||
svc := &services.Service{
|
||||
Port: 2345,
|
||||
@@ -338,12 +338,12 @@ func TestEngine_SendHiddenService(t *testing.T) {
|
||||
time.Now().Add(time.Hour), returner, introducer, svc,
|
||||
func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.W.S("received intro", reflect.TypeOf(ifc), b.ToBytes())
|
||||
// This happens when the gossip gets back to us.
|
||||
wg.Done()
|
||||
//wg.Done()
|
||||
counter.Dec()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
//wg.Wait()
|
||||
time.Sleep(time.Second)
|
||||
quit.Q()
|
||||
cancel()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gookit/color"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/node"
|
||||
"github.com/indra-labs/indra/pkg/engine/onions"
|
||||
@@ -9,7 +10,6 @@ import (
|
||||
"github.com/indra-labs/indra/pkg/util/cryptorand"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
// BuyNewSessions performs the initial purchase of 5 sessions as well as adding
|
||||
|
||||
@@ -3,14 +3,11 @@ package engine
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/engine/onions"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
@@ -289,311 +286,311 @@ func TestClient_SendSessionKeys(t *testing.T) {
|
||||
cancel()
|
||||
}
|
||||
|
||||
func TestEngine_Message(t *testing.T) {
|
||||
log2.SetLogLevel(log2.Debug)
|
||||
log2.App.Store("")
|
||||
var clients []*Engine
|
||||
var e error
|
||||
const nCircuits = 10
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
if clients, e = CreateNMockCircuits(nCircuits, nCircuits,
|
||||
ctx); fails(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
}
|
||||
client := clients[0]
|
||||
log.W.Ln("client", client.Manager.GetLocalNodeAddressString())
|
||||
// Start up the clients.
|
||||
for _, v := range clients {
|
||||
go v.Start()
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
var counter atomic.Int32
|
||||
quit := qu.T()
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 5):
|
||||
quit.Q()
|
||||
t.Error("MakeHiddenService test failed")
|
||||
case <-quit:
|
||||
for i := 0; i < int(counter.Load()); i++ {
|
||||
wg.Done()
|
||||
}
|
||||
for _, v := range clients {
|
||||
v.Shutdown()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
for i := 0; i < nCircuits*nCircuits/2; i++ {
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
e = client.BuyNewSessions(1000000, func() {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
})
|
||||
if fails(e) {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
var idPrv *crypto.Prv
|
||||
_ = idPrv
|
||||
if idPrv, e = crypto.GeneratePrvKey(); fails(e) {
|
||||
return
|
||||
}
|
||||
id := nonce.NewID()
|
||||
_ = id
|
||||
introducerHops := client.Manager.GetSessionsAtHop(2)
|
||||
var introducer *sessions.Data
|
||||
returnHops := client.Manager.GetSessionsAtHop(5)
|
||||
var returner *sessions.Data
|
||||
_ = returner
|
||||
if len(introducerHops) > 1 {
|
||||
cryptorand.Shuffle(len(introducerHops),
|
||||
func(i, j int) {
|
||||
introducerHops[i], introducerHops[j] =
|
||||
introducerHops[j], introducerHops[i]
|
||||
},
|
||||
)
|
||||
}
|
||||
introducer = introducerHops[0]
|
||||
if len(returnHops) > 1 {
|
||||
cryptorand.Shuffle(len(returnHops), func(i, j int) {
|
||||
returnHops[i], returnHops[j] = returnHops[j],
|
||||
returnHops[i]
|
||||
})
|
||||
}
|
||||
returner = returnHops[0]
|
||||
const localPort = 25234
|
||||
log.D.Ln("getting sessions for introducer...")
|
||||
for i := range clients {
|
||||
if introducer.Node.ID == clients[i].Manager.GetLocalNode().ID {
|
||||
for j := 0; j < nCircuits; j++ {
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
e = clients[i].BuyNewSessions(1000000, func() {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
})
|
||||
if fails(e) {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
break
|
||||
}
|
||||
}
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
svc := &services.Service{
|
||||
Port: 2345,
|
||||
RelayRate: 43523,
|
||||
Transport: transport.NewByteChan(64),
|
||||
}
|
||||
ini := client.SendHiddenService(id, idPrv, 0, 0,
|
||||
time.Now().Add(time.Hour), returner, introducer, svc,
|
||||
func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.I.F("hidden service %s successfully propagated", ifc)
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
time.Sleep(time.Second)
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
var rd *onions.Ready
|
||||
client.SendRoute(ini.Key, ini.AddrPort,
|
||||
func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
rd = ifc.(*onions.Ready)
|
||||
log.D.S("route pending", rd.Address, rd.Return)
|
||||
counter.Dec()
|
||||
wg.Done()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
log2.SetLogLevel(log2.Debug)
|
||||
msg, _, _ := tests.GenMessage(256, "hidden service message test")
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
var ms *onions.Message
|
||||
client.SendMessage(&onions.Message{
|
||||
Address: rd.Address,
|
||||
ID: nonce.NewID(),
|
||||
Re: rd.ID,
|
||||
Forward: rd.Return,
|
||||
Return: MakeReplyHeader(client),
|
||||
Payload: msg,
|
||||
}, func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.D.S("request success", id, ifc)
|
||||
ms = ifc.(*onions.Message)
|
||||
counter.Dec()
|
||||
wg.Done()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
client.SendMessage(&onions.Message{
|
||||
Address: ms.Address,
|
||||
ID: nonce.NewID(),
|
||||
Re: ms.ID,
|
||||
Forward: ms.Return,
|
||||
Return: MakeReplyHeader(client),
|
||||
Payload: msg,
|
||||
}, func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.D.S("response success", id, ifc)
|
||||
counter.Dec()
|
||||
wg.Done()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
time.Sleep(time.Second)
|
||||
quit.Q()
|
||||
cancel()
|
||||
log.W.Ln("fin")
|
||||
}
|
||||
//func TestEngine_Message(t *testing.T) {
|
||||
// log2.SetLogLevel(log2.Debug)
|
||||
// log2.App.Store("")
|
||||
// var clients []*Engine
|
||||
// var e error
|
||||
// const nCircuits = 10
|
||||
// ctx, cancel := context.WithCancel(context.Background())
|
||||
// if clients, e = CreateNMockCircuits(nCircuits, nCircuits,
|
||||
// ctx); fails(e) {
|
||||
// t.Error(e)
|
||||
// t.FailNow()
|
||||
// }
|
||||
// client := clients[0]
|
||||
// log.W.Ln("client", client.Manager.GetLocalNodeAddressString())
|
||||
// // Start up the clients.
|
||||
// for _, v := range clients {
|
||||
// go v.Start()
|
||||
// }
|
||||
// var wg sync.WaitGroup
|
||||
// var counter atomic.Int32
|
||||
// quit := qu.T()
|
||||
// go func() {
|
||||
// for {
|
||||
// select {
|
||||
// case <-time.After(time.Second * 5):
|
||||
// quit.Q()
|
||||
// t.Error("MakeHiddenService test failed")
|
||||
// case <-quit:
|
||||
// for i := 0; i < int(counter.Load()); i++ {
|
||||
// wg.Done()
|
||||
// }
|
||||
// for _, v := range clients {
|
||||
// v.Shutdown()
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// for i := 0; i < nCircuits*nCircuits/2; i++ {
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// e = client.BuyNewSessions(1000000, func() {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// })
|
||||
// if fails(e) {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// }
|
||||
// wg.Wait()
|
||||
// }
|
||||
// var idPrv *crypto.Prv
|
||||
// _ = idPrv
|
||||
// if idPrv, e = crypto.GeneratePrvKey(); fails(e) {
|
||||
// return
|
||||
// }
|
||||
// id := nonce.NewID()
|
||||
// _ = id
|
||||
// introducerHops := client.Manager.GetSessionsAtHop(2)
|
||||
// var introducer *sessions.Data
|
||||
// returnHops := client.Manager.GetSessionsAtHop(5)
|
||||
// var returner *sessions.Data
|
||||
// _ = returner
|
||||
// if len(introducerHops) > 1 {
|
||||
// cryptorand.Shuffle(len(introducerHops),
|
||||
// func(i, j int) {
|
||||
// introducerHops[i], introducerHops[j] =
|
||||
// introducerHops[j], introducerHops[i]
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
// introducer = introducerHops[0]
|
||||
// if len(returnHops) > 1 {
|
||||
// cryptorand.Shuffle(len(returnHops), func(i, j int) {
|
||||
// returnHops[i], returnHops[j] = returnHops[j],
|
||||
// returnHops[i]
|
||||
// })
|
||||
// }
|
||||
// returner = returnHops[0]
|
||||
// const localPort = 25234
|
||||
// log.D.Ln("getting sessions for introducer...")
|
||||
// for i := range clients {
|
||||
// if introducer.Node.ID == clients[i].Manager.GetLocalNode().ID {
|
||||
// for j := 0; j < nCircuits; j++ {
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// e = clients[i].BuyNewSessions(1000000, func() {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// })
|
||||
// if fails(e) {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// }
|
||||
// }
|
||||
// wg.Wait()
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// svc := &services.Service{
|
||||
// Port: 2345,
|
||||
// RelayRate: 43523,
|
||||
// Transport: transport.NewByteChan(64),
|
||||
// }
|
||||
// ini := client.SendHiddenService(id, idPrv, 0, 0,
|
||||
// time.Now().Add(time.Hour), returner, introducer, svc,
|
||||
// func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
// log.I.F("hidden service %s successfully propagated", ifc)
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// return
|
||||
// })
|
||||
// wg.Wait()
|
||||
// time.Sleep(time.Second)
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// var rd *onions.Ready
|
||||
// client.SendRoute(ini.Key, ini.AddrPort,
|
||||
// func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
// rd = ifc.(*onions.Ready)
|
||||
// log.D.S("route pending", rd.Address, rd.Return)
|
||||
// counter.Dec()
|
||||
// wg.Done()
|
||||
// return
|
||||
// })
|
||||
// wg.Wait()
|
||||
// log2.SetLogLevel(log2.Debug)
|
||||
// msg, _, _ := tests.GenMessage(256, "hidden service message test")
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// var ms *onions.Message
|
||||
// client.SendMessage(&onions.Message{
|
||||
// Address: rd.Address,
|
||||
// ID: nonce.NewID(),
|
||||
// Re: rd.ID,
|
||||
// Forward: rd.Return,
|
||||
// Return: MakeReplyHeader(client),
|
||||
// Payload: msg,
|
||||
// }, func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
// log.D.S("request success", id, ifc)
|
||||
// ms = ifc.(*onions.Message)
|
||||
// counter.Dec()
|
||||
// wg.Done()
|
||||
// return
|
||||
// })
|
||||
// wg.Wait()
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// client.SendMessage(&onions.Message{
|
||||
// Address: ms.Address,
|
||||
// ID: nonce.NewID(),
|
||||
// Re: ms.ID,
|
||||
// Forward: ms.Return,
|
||||
// Return: MakeReplyHeader(client),
|
||||
// Payload: msg,
|
||||
// }, func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
// log.D.S("response success", id, ifc)
|
||||
// counter.Dec()
|
||||
// wg.Done()
|
||||
// return
|
||||
// })
|
||||
// wg.Wait()
|
||||
// time.Sleep(time.Second)
|
||||
// quit.Q()
|
||||
// cancel()
|
||||
// log.W.Ln("fin")
|
||||
//}
|
||||
|
||||
func TestEngine_Route(t *testing.T) {
|
||||
log2.SetLogLevel(log2.Debug)
|
||||
log2.App.Store("")
|
||||
runtime.GOMAXPROCS(1)
|
||||
var clients []*Engine
|
||||
var e error
|
||||
const nCircuits = 10
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
if clients, e = CreateNMockCircuits(nCircuits, nCircuits,
|
||||
ctx); fails(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
}
|
||||
client := clients[0]
|
||||
log.W.Ln("client", client.Manager.GetLocalNodeAddressString())
|
||||
// Start up the clients.
|
||||
for _, v := range clients {
|
||||
go v.Start()
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
var counter atomic.Int32
|
||||
quit := qu.T()
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 4):
|
||||
quit.Q()
|
||||
t.Error("Route test failed")
|
||||
case <-quit:
|
||||
for i := 0; i < int(counter.Load()); i++ {
|
||||
wg.Done()
|
||||
}
|
||||
for _, v := range clients {
|
||||
v.Shutdown()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
for i := 0; i < nCircuits*nCircuits/2; i++ {
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
e = client.BuyNewSessions(1000000, func() {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
})
|
||||
if fails(e) {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
var idPrv *crypto.Prv
|
||||
_ = idPrv
|
||||
if idPrv, e = crypto.GeneratePrvKey(); fails(e) {
|
||||
return
|
||||
}
|
||||
id := nonce.NewID()
|
||||
_ = id
|
||||
introducerHops := client.Manager.GetSessionsAtHop(2)
|
||||
var introducer *sessions.Data
|
||||
returnHops := client.Manager.GetSessionsAtHop(5)
|
||||
var returner *sessions.Data
|
||||
_ = returner
|
||||
if len(introducerHops) > 1 {
|
||||
cryptorand.Shuffle(len(introducerHops),
|
||||
func(i, j int) {
|
||||
introducerHops[i], introducerHops[j] =
|
||||
introducerHops[j], introducerHops[i]
|
||||
},
|
||||
)
|
||||
}
|
||||
introducer = introducerHops[0]
|
||||
if len(returnHops) > 1 {
|
||||
cryptorand.Shuffle(len(returnHops), func(i, j int) {
|
||||
returnHops[i], returnHops[j] = returnHops[j],
|
||||
returnHops[i]
|
||||
})
|
||||
}
|
||||
returner = returnHops[0]
|
||||
const localPort = 25234
|
||||
log.D.Ln("getting sessions for introducer...")
|
||||
for i := range clients {
|
||||
if introducer.Node.ID == clients[i].Manager.GetLocalNode().ID {
|
||||
for j := 0; j < nCircuits; j++ {
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
e = clients[i].BuyNewSessions(1000000, func() {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
})
|
||||
if fails(e) {
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
break
|
||||
}
|
||||
}
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
svc := &services.Service{
|
||||
Port: localPort,
|
||||
RelayRate: 43523,
|
||||
Transport: transport.NewByteChan(64),
|
||||
}
|
||||
ini := client.SendHiddenService(id, idPrv, 0, 0,
|
||||
time.Now().Add(time.Hour),
|
||||
returner, introducer, svc,
|
||||
func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.I.F("hidden service %s successfully propagated", ifc)
|
||||
wg.Done()
|
||||
counter.Dec()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
time.Sleep(time.Second)
|
||||
log2.SetLogLevel(log2.Debug)
|
||||
wg.Add(1)
|
||||
counter.Inc()
|
||||
log.D.Ln("intro", ini.ID, ini.AddrPort.String(), ini.Key.ToBased32Abbreviated(),
|
||||
ini.Expiry, ini.Validate())
|
||||
client.SendRoute(ini.Key, ini.AddrPort,
|
||||
func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.I.S("success", id)
|
||||
counter.Dec()
|
||||
wg.Done()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
quit.Q()
|
||||
cancel()
|
||||
log.W.Ln("fin")
|
||||
}
|
||||
//func TestEngine_Route(t *testing.T) {
|
||||
// log2.SetLogLevel(log2.Debug)
|
||||
// log2.App.Store("")
|
||||
// runtime.GOMAXPROCS(1)
|
||||
// var clients []*Engine
|
||||
// var e error
|
||||
// const nCircuits = 10
|
||||
// ctx, cancel := context.WithCancel(context.Background())
|
||||
// if clients, e = CreateNMockCircuits(nCircuits, nCircuits,
|
||||
// ctx); fails(e) {
|
||||
// t.Error(e)
|
||||
// t.FailNow()
|
||||
// }
|
||||
// client := clients[0]
|
||||
// log.W.Ln("client", client.Manager.GetLocalNodeAddressString())
|
||||
// // Start up the clients.
|
||||
// for _, v := range clients {
|
||||
// go v.Start()
|
||||
// }
|
||||
// var wg sync.WaitGroup
|
||||
// var counter atomic.Int32
|
||||
// quit := qu.T()
|
||||
// go func() {
|
||||
// for {
|
||||
// select {
|
||||
// case <-time.After(time.Second * 4):
|
||||
// quit.Q()
|
||||
// t.Error("Route test failed")
|
||||
// case <-quit:
|
||||
// for i := 0; i < int(counter.Load()); i++ {
|
||||
// wg.Done()
|
||||
// }
|
||||
// for _, v := range clients {
|
||||
// v.Shutdown()
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// for i := 0; i < nCircuits*nCircuits/2; i++ {
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// e = client.BuyNewSessions(1000000, func() {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// })
|
||||
// if fails(e) {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// }
|
||||
// wg.Wait()
|
||||
// }
|
||||
// var idPrv *crypto.Prv
|
||||
// _ = idPrv
|
||||
// if idPrv, e = crypto.GeneratePrvKey(); fails(e) {
|
||||
// return
|
||||
// }
|
||||
// id := nonce.NewID()
|
||||
// _ = id
|
||||
// introducerHops := client.Manager.GetSessionsAtHop(2)
|
||||
// var introducer *sessions.Data
|
||||
// returnHops := client.Manager.GetSessionsAtHop(5)
|
||||
// var returner *sessions.Data
|
||||
// _ = returner
|
||||
// if len(introducerHops) > 1 {
|
||||
// cryptorand.Shuffle(len(introducerHops),
|
||||
// func(i, j int) {
|
||||
// introducerHops[i], introducerHops[j] =
|
||||
// introducerHops[j], introducerHops[i]
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
// introducer = introducerHops[0]
|
||||
// if len(returnHops) > 1 {
|
||||
// cryptorand.Shuffle(len(returnHops), func(i, j int) {
|
||||
// returnHops[i], returnHops[j] = returnHops[j],
|
||||
// returnHops[i]
|
||||
// })
|
||||
// }
|
||||
// returner = returnHops[0]
|
||||
// const localPort = 25234
|
||||
// log.D.Ln("getting sessions for introducer...")
|
||||
// for i := range clients {
|
||||
// if introducer.Node.ID == clients[i].Manager.GetLocalNode().ID {
|
||||
// for j := 0; j < nCircuits; j++ {
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// e = clients[i].BuyNewSessions(1000000, func() {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// })
|
||||
// if fails(e) {
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// }
|
||||
// }
|
||||
// wg.Wait()
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// svc := &services.Service{
|
||||
// Port: localPort,
|
||||
// RelayRate: 43523,
|
||||
// Transport: transport.NewByteChan(64),
|
||||
// }
|
||||
// ini := client.SendHiddenService(id, idPrv, 0, 0,
|
||||
// time.Now().Add(time.Hour),
|
||||
// returner, introducer, svc,
|
||||
// func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
// log.I.F("hidden service %s successfully propagated", ifc)
|
||||
// wg.Done()
|
||||
// counter.Dec()
|
||||
// return
|
||||
// })
|
||||
// wg.Wait()
|
||||
// time.Sleep(time.Second)
|
||||
// log2.SetLogLevel(log2.Debug)
|
||||
// wg.Add(1)
|
||||
// counter.Inc()
|
||||
// log.D.Ln("intro", ini.ID, ini.AddrPort.String(), ini.Key.ToBased32Abbreviated(),
|
||||
// ini.Expiry, ini.Validate())
|
||||
// client.SendRoute(ini.Key, ini.AddrPort,
|
||||
// func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
// log.I.S("success", id)
|
||||
// counter.Dec()
|
||||
// wg.Done()
|
||||
// return
|
||||
// })
|
||||
// wg.Wait()
|
||||
// quit.Q()
|
||||
// cancel()
|
||||
// log.W.Ln("fin")
|
||||
//}
|
||||
|
||||
func TestEngine_SendHiddenService(t *testing.T) {
|
||||
log2.SetLogLevel(log2.Debug)
|
||||
@@ -668,7 +665,7 @@ func TestEngine_SendHiddenService(t *testing.T) {
|
||||
// index of introducerHops will be a randomly selected one.
|
||||
introducer = introducerHops[0]
|
||||
returner = returnHops[0]
|
||||
wg.Add(1)
|
||||
//wg.Add(1)
|
||||
counter.Inc()
|
||||
svc := &services.Service{
|
||||
Port: 2345,
|
||||
@@ -680,11 +677,12 @@ func TestEngine_SendHiddenService(t *testing.T) {
|
||||
func(id nonce.ID, ifc interface{}, b slice.Bytes) (e error) {
|
||||
log.W.S("received intro", reflect.TypeOf(ifc), b.ToBytes())
|
||||
// This happens when the gossip gets back to us.
|
||||
wg.Done()
|
||||
//wg.Done()
|
||||
counter.Dec()
|
||||
return
|
||||
})
|
||||
wg.Wait()
|
||||
//wg.Wait()
|
||||
time.Sleep(time.Second)
|
||||
quit.Q()
|
||||
cancel()
|
||||
}
|
||||
|
||||
86
pkg/engine/onions/adaddress.go
Normal file
86
pkg/engine/onions/adaddress.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"net/netip"
|
||||
"time"
|
||||
)
|
||||
const AddressAdLen = nonce.IDLen +
|
||||
splice.AddrLen + 1 +
|
||||
slice.Uint64Len +
|
||||
crypto.SigLen
|
||||
|
||||
// Address entries are stored with an index generated by concatenating the bytes
|
||||
// of the public key with a string path "/address/N" where N is the index of the
|
||||
// address. This means hidden service introducers for values over zero.
|
||||
// Hidden services have no value in the zero index, which is "<hash>/address/0".
|
||||
type Address struct {
|
||||
ID nonce.ID // To ensure no repeating message
|
||||
Multiaddr multiaddr.Multiaddr // We only use a netip.AddrPort though.
|
||||
Index byte // This is the index in the slice from Peer.
|
||||
Expiry time.Time // zero for relay's public address (32 bit).
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func (a *Address) Decode(s *splice.Splice) (e error) {
|
||||
var addr *netip.AddrPort
|
||||
s.ReadID(&a.ID).ReadAddrPort(&addr).ReadByte(&a.Index).ReadTime(&a.Expiry)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Address) Encode(s *splice.Splice) (e error) {
|
||||
var ip, port string
|
||||
if ip, e = a.Multiaddr.ValueForProtocol(multiaddr.P_IP4); fails(e) {
|
||||
}
|
||||
if ip == "" {
|
||||
if ip, e = a.Multiaddr.ValueForProtocol(multiaddr.P_IP6); fails(e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if port, e = a.Multiaddr.ValueForProtocol(multiaddr.P_TCP); fails(e) {
|
||||
return
|
||||
}
|
||||
var addr netip.AddrPort
|
||||
if addr, e = netip.ParseAddrPort(ip + ":" + port); fails(e) {
|
||||
}
|
||||
s.ID(a.ID).AddrPort(&addr).Byte(a.Index).Time(a.Expiry)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Address) GetOnion() interface{} { return nil }
|
||||
|
||||
func (a *Address) Len() int { return AddressAdLen }
|
||||
|
||||
func (a *Address) Magic() string { return "" }
|
||||
|
||||
func (a *Address) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(a.Len())
|
||||
if e = a.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(a.Sig[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Address) Validate(s *splice.Splice) (pub *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+splice.AddrLen+1+
|
||||
slice.Uint64Len))
|
||||
var e error
|
||||
if pub, e = a.Sig.Recover(h); fails(e) {
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -5,14 +5,11 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/color"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/engine/node"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
@@ -76,18 +73,25 @@ func (x *Intro) Encode(s *splice.Splice) (e error) {
|
||||
|
||||
func (x *Intro) GetOnion() interface{} { return x }
|
||||
|
||||
// Gossip means adding to the node's peer message list which will be gossiped by
|
||||
// the libp2p network of Indra peers.
|
||||
func (x *Intro) Gossip(sm *sess.Manager, c qu.C) {
|
||||
log.D.F("propagating hidden service intro for %s",
|
||||
x.Key.ToBased32Abbreviated())
|
||||
Gossip(x, sm, c)
|
||||
log.T.Ln("finished broadcasting intro")
|
||||
//Gossip(x, sm, c)
|
||||
//log.T.Ln("finished broadcasting intro")
|
||||
}
|
||||
|
||||
func (x *Intro) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
|
||||
log.D.Ln("handling intro")
|
||||
ng.GetHidden().Lock()
|
||||
valid := x.Validate()
|
||||
if valid {
|
||||
log.T.Ln(ng.Mgr().GetLocalNodeAddressString(), "validated intro", x.ID)
|
||||
|
||||
// Add to our current peer state advertisements.
|
||||
_ = valid
|
||||
|
||||
log.D.Ln(ng.Mgr().GetLocalNodeAddressString(), "validated intro", x.ID)
|
||||
kb := x.Key.ToBytes()
|
||||
if _, ok := ng.GetHidden().KnownIntros[x.Key.ToBytes()]; ok {
|
||||
log.D.Ln(ng.Mgr().GetLocalNodeAddressString(), "already have intro")
|
||||
@@ -101,35 +105,35 @@ func (x *Intro) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
|
||||
ng.GetHidden().KnownIntros[x.Key.ToBytes()] = x
|
||||
var ok bool
|
||||
if ok, e = ng.Pending().ProcessAndDelete(x.ID, &kb,
|
||||
s.GetAll()); ok || fails(e) {
|
||||
s.GetAll()); ok || !fails(e) {
|
||||
|
||||
ng.GetHidden().Unlock()
|
||||
log.D.Ln("deleted pending response", x.ID)
|
||||
return
|
||||
}
|
||||
log.D.F("%s sending out intro to %s at %s to all known peers",
|
||||
ng.Mgr().GetLocalNodeAddressString(), x.Key.ToBased32Abbreviated(),
|
||||
color.Yellow.Sprint(x.AddrPort.String()))
|
||||
sender := ng.Mgr().FindNodeByAddrPort(x.AddrPort)
|
||||
nn := make(map[nonce.ID]*node.Node)
|
||||
ng.Mgr().ForEachNode(func(n *node.Node) bool {
|
||||
if n.ID != sender.ID {
|
||||
nn[n.ID] = n
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
counter := 0
|
||||
for i := range nn {
|
||||
log.T.F("sending intro to %s", color.Yellow.Sprint(nn[i].AddrPort.
|
||||
String()))
|
||||
nn[i].Transport.Send(s.GetAll())
|
||||
counter++
|
||||
if counter < 2 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
//log.D.F("%s sending out intro to %s at %s to all known peers",
|
||||
// ng.Mgr().GetLocalNodeAddressString(), x.Key.ToBased32Abbreviated(),
|
||||
// color.Yellow.Sprint(x.AddrPort.String()))
|
||||
//sender := ng.Mgr().FindNodeByAddrPort(x.AddrPort)
|
||||
//nn := make(map[nonce.ID]*node.Node)
|
||||
//ng.Mgr().ForEachNode(func(n *node.Node) bool {
|
||||
// if n.ID != sender.ID {
|
||||
// nn[n.ID] = n
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
//})
|
||||
//counter := 0
|
||||
//for i := range nn {
|
||||
// log.T.F("sending intro to %s", color.Yellow.Sprint(nn[i].AddrPort.
|
||||
// String()))
|
||||
// nn[i].Transport.Send(s.GetAll())
|
||||
// counter++
|
||||
// if counter < 2 {
|
||||
// continue
|
||||
// }
|
||||
// break
|
||||
//}
|
||||
}
|
||||
ng.GetHidden().Unlock()
|
||||
return
|
||||
86
pkg/engine/onions/adpeer.go
Normal file
86
pkg/engine/onions/adpeer.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
)
|
||||
|
||||
const PeerAdLen = magic.Len +
|
||||
nonce.IDLen +
|
||||
slice.Uint64Len +
|
||||
crypto.SigLen
|
||||
|
||||
// PeerAd is the root identity document for an Indra peer. It is indexed by the
|
||||
// Identity field, its public key. The slices found below it are derived via
|
||||
// concatenation of strings with the keys and hashing to generate a derived
|
||||
// field index, used to search the DHT for matches.
|
||||
//
|
||||
// The data stored for Peer must be signed with the key claimed by the Identity.
|
||||
// For hidden services the address fields are signed in the DHT by the hidden
|
||||
// service from their introduction solicitation, and the index from the current
|
||||
// set is given by the hidden service.
|
||||
type PeerAd struct {
|
||||
nonce.ID // To ensure no repeating message
|
||||
Identity crypto.PubBytes
|
||||
RelayRate int
|
||||
Sig crypto.SigBytes
|
||||
// Addresses - first is address, nil for hidden services,
|
||||
// hidden services have more than one, 6 or more are kept active.
|
||||
Addresses []*Address
|
||||
ServiceInfos []ServiceAd
|
||||
}
|
||||
|
||||
func (p *PeerAd) Decode(s *splice.Splice) (e error) {
|
||||
var v uint64
|
||||
s.ReadID(&p.ID).ReadUint64(&v)
|
||||
s.ReadSignature(&p.Sig)
|
||||
p.RelayRate = int(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PeerAd) Encode(s *splice.Splice) (e error) {
|
||||
s.ID(p.ID).Uint64(uint64(p.RelayRate))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PeerAd) GetOnion() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PeerAd) Len() int {
|
||||
return PeerAdLen
|
||||
}
|
||||
|
||||
func (p *PeerAd) Magic() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *PeerAd) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(p.Len())
|
||||
if e = p.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(p.Sig[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PeerAd) Validate(s *splice.Splice) (pk *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+slice.Uint64Len))
|
||||
var e error
|
||||
if pk, e = p.Sig.Recover(h); fails(e) {
|
||||
}
|
||||
return
|
||||
}
|
||||
73
pkg/engine/onions/adservice.go
Normal file
73
pkg/engine/onions/adservice.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
)
|
||||
|
||||
const ServiceAdLen = nonce.IDLen +
|
||||
2*slice.Uint16Len +
|
||||
slice.Uint32Len +
|
||||
crypto.SigLen
|
||||
|
||||
// ServiceAd stores a specification for the fee rate and the service port, which
|
||||
// must be a well known port to match with a type of service, eg 80 for web, 53
|
||||
// for DNS, etc. These are also attached to the Peer entry via concatenating
|
||||
// "/service/N" where N is the index of the entry. A zero value at an index
|
||||
// signals to stop scanning for more subsequent values.
|
||||
type ServiceAd struct {
|
||||
ID nonce.ID // To ensure no repeating message
|
||||
Index uint16 // This is the index in the slice from Peer.
|
||||
Port uint16
|
||||
RelayRate uint32
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func (sv *ServiceAd) Decode(s *splice.Splice) (e error) {
|
||||
s.ReadID(&sv.ID).
|
||||
ReadUint16(&sv.Index).
|
||||
ReadUint16(&sv.Port).
|
||||
ReadUint32(&sv.RelayRate)
|
||||
return
|
||||
}
|
||||
|
||||
func (sv *ServiceAd) Encode(s *splice.Splice) (e error) {
|
||||
s.ID(sv.ID).Uint16(sv.Index).Uint16(sv.Port).Uint32(sv.RelayRate)
|
||||
return
|
||||
}
|
||||
|
||||
func (sv *ServiceAd) GetOnion() interface{} { return nil }
|
||||
|
||||
func (sv *ServiceAd) Len() int { return ServiceAdLen }
|
||||
|
||||
func (sv *ServiceAd) Magic() string { return "" }
|
||||
|
||||
func (sv *ServiceAd) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(sv.Len())
|
||||
if e = sv.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(sv.Sig[:], b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sv *ServiceAd) Validate(s *splice.Splice) (pub *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+2*slice.Uint16Len+
|
||||
slice.Uint64Len))
|
||||
var e error
|
||||
if pub, e = sv.Sig.Recover(h); fails(e) {
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
|
||||
@@ -2,7 +2,7 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
|
||||
@@ -2,7 +2,7 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
|
||||
@@ -3,7 +3,7 @@ package onions
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ package onions
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
|
||||
41
pkg/engine/onions/gossip.go
Normal file
41
pkg/engine/onions/gossip.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"github.com/indra-labs/indra/pkg/util/cryptorand"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
)
|
||||
|
||||
func Gossip(x Ad, sm *sess.Manager, c qu.C) {
|
||||
done := qu.T()
|
||||
msg := splice.New(x.Len())
|
||||
if fails(x.Encode(msg)) {
|
||||
return
|
||||
}
|
||||
nPeers := sm.NodesLen()
|
||||
peerIndices := make([]int, nPeers)
|
||||
for i := 1; i < nPeers; i++ {
|
||||
peerIndices[i] = i
|
||||
}
|
||||
cryptorand.Shuffle(nPeers, func(i, j int) {
|
||||
peerIndices[i], peerIndices[j] = peerIndices[j], peerIndices[i]
|
||||
})
|
||||
var cursor int
|
||||
for {
|
||||
select {
|
||||
case <-c.Wait():
|
||||
return
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
}
|
||||
n := sm.FindNodeByIndex(peerIndices[cursor])
|
||||
n.Transport.Send(msg.GetAll())
|
||||
cursor++
|
||||
if cursor > len(peerIndices)-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func (hr *Hidden) DeleteKnownIntro(key crypto.PubBytes) (
|
||||
func (hr *Hidden) FindCloakedHiddenService(key crypto.PubKey) (
|
||||
pubKey *crypto.PubBytes) {
|
||||
for i := range hr.MyIntros {
|
||||
pubKey1 := hr.MyIntros[i].Key.ToBytes()
|
||||
pubKey1 := hr.MyIntros[i].Intro.Key.ToBytes()
|
||||
if crypto.Match(key, pubKey1) {
|
||||
return &pubKey1
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const (
|
||||
)
|
||||
|
||||
type HiddenService struct {
|
||||
Intro
|
||||
Intro Intro
|
||||
// Ciphers is a set of 3 symmetric ciphers that are to be used in their
|
||||
// given order over the reply message from the service.
|
||||
crypto.Ciphers
|
||||
@@ -58,7 +58,7 @@ func (x *HiddenService) Decode(s *splice.Splice) (e error) {
|
||||
|
||||
func (x *HiddenService) Encode(s *splice.Splice) (e error) {
|
||||
log.T.S("encoding", reflect.TypeOf(x),
|
||||
x.ID, x.Key, x.AddrPort, x.Ciphers, x.Nonces, x.RoutingHeaderBytes,
|
||||
x.Intro.ID, x.Intro.Key, x.Intro.AddrPort, x.Ciphers, x.Nonces, x.RoutingHeaderBytes,
|
||||
)
|
||||
x.Intro.Splice(s.Magic(HiddenServiceMagic))
|
||||
return x.Onion.Encode(s.Ciphers(x.Ciphers).Nonces(x.Nonces))
|
||||
@@ -68,8 +68,8 @@ func (x *HiddenService) GetOnion() interface{} { return x }
|
||||
|
||||
func (x *HiddenService) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
|
||||
log.D.F("%s adding introduction for key %s",
|
||||
ng.Mgr().GetLocalNodeAddressString(), x.Key.ToBased32Abbreviated())
|
||||
ng.GetHidden().AddIntro(x.Key, &Introduction{
|
||||
ng.Mgr().GetLocalNodeAddressString(), x.Intro.Key.ToBased32Abbreviated())
|
||||
ng.GetHidden().AddIntro(x.Intro.Key, &Introduction{
|
||||
Intro: &x.Intro,
|
||||
ReplyHeader: ReplyHeader{
|
||||
Ciphers: x.Ciphers,
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"github.com/indra-labs/indra/pkg/util/cryptorand"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/responses"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
)
|
||||
|
||||
type Ngin interface {
|
||||
@@ -33,41 +31,9 @@ type Onion interface {
|
||||
Account(res *sess.Data, sm *sess.Manager, s *sessions.Data,
|
||||
last bool) (skip bool, sd *sessions.Data)
|
||||
}
|
||||
type PeerInfo interface {
|
||||
type Ad interface {
|
||||
Onion
|
||||
Splice(s *splice.Splice)
|
||||
Validate() bool
|
||||
Gossip(sm *sess.Manager, c qu.C)
|
||||
}
|
||||
|
||||
func Gossip(x PeerInfo, sm *sess.Manager, c qu.C) {
|
||||
done := qu.T()
|
||||
msg := splice.New(x.Len())
|
||||
if fails(x.Encode(msg)) {
|
||||
return
|
||||
}
|
||||
nPeers := sm.NodesLen()
|
||||
peerIndices := make([]int, nPeers)
|
||||
for i := 1; i < nPeers; i++ {
|
||||
peerIndices[i] = i
|
||||
}
|
||||
cryptorand.Shuffle(nPeers, func(i, j int) {
|
||||
peerIndices[i], peerIndices[j] = peerIndices[j], peerIndices[i]
|
||||
})
|
||||
var cursor int
|
||||
for {
|
||||
select {
|
||||
case <-c.Wait():
|
||||
return
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
}
|
||||
n := sm.FindNodeByIndex(peerIndices[cursor])
|
||||
n.Transport.Send(msg.GetAll())
|
||||
cursor++
|
||||
if cursor > len(peerIndices)-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package onions
|
||||
|
||||
type Introduction struct {
|
||||
*Intro
|
||||
Intro *Intro
|
||||
ReplyHeader
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/ciph"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
@@ -11,7 +12,6 @@ import (
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"github.com/indra-labs/indra"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
@@ -15,7 +17,11 @@ import (
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
)
|
||||
|
||||
var nop = &End{}
|
||||
var (
|
||||
log = log2.GetLogger(indra.PathBase)
|
||||
fails = log.E.Chk
|
||||
nop = &End{}
|
||||
)
|
||||
|
||||
// Assemble inserts the slice of Layer s inside each other so the first then
|
||||
// contains the second, second contains the third, and so on, and then returns
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"github.com/indra-labs/indra"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gookit/color"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
log = log2.GetLogger(indra.PathBase)
|
||||
fails = log.E.Chk
|
||||
registry = NewRegistry()
|
||||
)
|
||||
var registry = NewRegistry()
|
||||
|
||||
type (
|
||||
CodecGenerators map[string]func() coding.Codec
|
||||
@@ -40,11 +35,11 @@ func Recognise(s *splice.Splice) (cdc coding.Codec) {
|
||||
cdc = in()
|
||||
}
|
||||
if !ok || cdc == nil {
|
||||
// log.D.F("unrecognised magic %s ignoring message",
|
||||
// color.Red.Sprint(magic),
|
||||
// spew.Sdump(s.GetUntil(s.GetCursor()).ToBytes()),
|
||||
// spew.Sdump(s.GetFrom(s.GetCursor()).ToBytes()),
|
||||
// )
|
||||
log.D.F("unrecognised magic %s ignoring message",
|
||||
color.Red.Sprint(magic),
|
||||
spew.Sdump(s.GetUntil(s.GetCursor()).ToBytes()),
|
||||
spew.Sdump(s.GetFrom(s.GetCursor()).ToBytes()),
|
||||
)
|
||||
} else {
|
||||
log.T.F("recognised magic %s for type %v",
|
||||
color.Red.Sprint(magic),
|
||||
|
||||
@@ -2,7 +2,7 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
)
|
||||
|
||||
@@ -100,6 +100,8 @@ func (p *Pending) GetOldestPending() (pr *Response) {
|
||||
|
||||
// ProcessAndDelete runs the callback and post accounting function list and
|
||||
// deletes the pending response.
|
||||
//
|
||||
// Returns true if it found and deleted a pending response.
|
||||
func (p *Pending) ProcessAndDelete(id nonce.ID, ifc interface{},
|
||||
b slice.Bytes) (found bool, e error) {
|
||||
p.Lock()
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
|
||||
const (
|
||||
LocalhostZeroIPv4TCP = "/ip4/127.0.0.1/tcp/0"
|
||||
// LocalhostZeroIPv4QUIC - Don't use. Buffer problems on linux and fails on CI.
|
||||
LocalhostZeroIPv4QUIC = "/ip4/127.0.0.1/udp/0/quic"
|
||||
DefaultMTU = 1382
|
||||
ConnBufs = 8192
|
||||
|
||||
12
version.go
12
version.go
@@ -1,5 +1,10 @@
|
||||
//go:build !local
|
||||
|
||||
// This can be overridden by a developer's version by setting the tag local.
|
||||
|
||||
package indra
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Put invocations to run all the generators in here (
|
||||
// check cmd/bumper/ to add them, and they will automatically run with:
|
||||
@@ -7,16 +12,11 @@ package indra
|
||||
// $ go generate .
|
||||
//
|
||||
// which will run all these generators below and finish with a go install.
|
||||
//go:generate go run ./pkg/relay/gen/main.go
|
||||
//go:generate go install ./...
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
// URL is the git URL for the repository.
|
||||
URL = ""
|
||||
URL = "github.com/indra-labs/indra"
|
||||
// GitRef is the gitref, as in refs/heads/branchname.
|
||||
GitRef = "refs/heads/master"
|
||||
// ParentGitCommit is the commit hash of the parent HEAD.
|
||||
|
||||
Reference in New Issue
Block a user