mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-23 13:38:35 +00:00
86 lines
2.5 KiB
Go
86 lines
2.5 KiB
Go
|
package broadcaster
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/base64"
|
||
|
"encoding/binary"
|
||
|
"time"
|
||
|
|
||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/services/oracle"
|
||
|
"go.uber.org/zap"
|
||
|
)
|
||
|
|
||
|
type rpcBroascaster struct {
|
||
|
clients map[string]*client.Client
|
||
|
log *zap.Logger
|
||
|
|
||
|
sendTimeout time.Duration
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
defaultSendTimeout = time.Second * 4
|
||
|
)
|
||
|
|
||
|
// New returns new struct capable of broadcasting oracle responses.
|
||
|
func New(cfg config.OracleConfiguration, log *zap.Logger) oracle.Broadcaster {
|
||
|
if cfg.ResponseTimeout == 0 {
|
||
|
cfg.ResponseTimeout = defaultSendTimeout
|
||
|
}
|
||
|
r := &rpcBroascaster{
|
||
|
clients: make(map[string]*client.Client, len(cfg.Nodes)),
|
||
|
log: log,
|
||
|
sendTimeout: cfg.ResponseTimeout,
|
||
|
}
|
||
|
for i := range cfg.Nodes {
|
||
|
// We ignore error as not every node can be available on startup.
|
||
|
r.clients[cfg.Nodes[i]], _ = client.New(context.Background(), "http://"+cfg.Nodes[i], client.Options{
|
||
|
DialTimeout: cfg.ResponseTimeout,
|
||
|
RequestTimeout: cfg.ResponseTimeout,
|
||
|
})
|
||
|
}
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
// SendResponse implements interfaces.Broadcaster.
|
||
|
func (r *rpcBroascaster) SendResponse(priv *keys.PrivateKey, resp *transaction.OracleResponse, txSig []byte) {
|
||
|
pub := priv.PublicKey()
|
||
|
data := GetMessage(pub.Bytes(), resp.ID, txSig)
|
||
|
msgSig := priv.Sign(data)
|
||
|
params := request.NewRawParams(
|
||
|
base64.StdEncoding.EncodeToString(pub.Bytes()),
|
||
|
resp.ID,
|
||
|
base64.StdEncoding.EncodeToString(txSig),
|
||
|
base64.StdEncoding.EncodeToString(msgSig),
|
||
|
)
|
||
|
for addr, c := range r.clients {
|
||
|
if c == nil {
|
||
|
var err error
|
||
|
c, err = client.New(context.Background(), addr, client.Options{
|
||
|
DialTimeout: r.sendTimeout,
|
||
|
RequestTimeout: r.sendTimeout,
|
||
|
})
|
||
|
if err != nil {
|
||
|
r.log.Debug("can't connect to oracle node", zap.String("address", addr), zap.Error(err))
|
||
|
continue
|
||
|
}
|
||
|
r.clients[addr] = c
|
||
|
}
|
||
|
err := c.SubmitRawOracleResponse(params)
|
||
|
r.log.Debug("error during oracle response submit", zap.String("address", addr), zap.Error(err))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// GetMessage returns data which is signed upon sending response by RPC.
|
||
|
func GetMessage(pubBytes []byte, reqID uint64, txSig []byte) []byte {
|
||
|
data := make([]byte, len(pubBytes)+8+len(txSig))
|
||
|
copy(data, pubBytes)
|
||
|
binary.LittleEndian.PutUint64(data[len(pubBytes):], uint64(reqID))
|
||
|
copy(data[len(pubBytes)+8:], txSig)
|
||
|
return data
|
||
|
}
|