mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
Merge db7285cacc into ed40767355
This commit is contained in:
commit
66777dbabd
53 changed files with 2099 additions and 2099 deletions
|
|
@ -38,12 +38,12 @@ type DirectoryString struct {
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DirectoryString) String() string {
|
func (s *DirectoryString) String() string {
|
||||||
return self.Value
|
return s.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DirectoryString) Set(value string) error {
|
func (s *DirectoryString) Set(value string) error {
|
||||||
self.Value = expandPath(value)
|
s.Value = expandPath(value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,12 +55,12 @@ type DirectoryFlag struct {
|
||||||
Usage string
|
Usage string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DirectoryFlag) String() string {
|
func (f DirectoryFlag) String() string {
|
||||||
fmtString := "%s %v\t%v"
|
fmtString := "%s %v\t%v"
|
||||||
if len(self.Value.Value) > 0 {
|
if len(f.Value.Value) > 0 {
|
||||||
fmtString = "%s \"%v\"\t%v"
|
fmtString = "%s \"%v\"\t%v"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)
|
return fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value.Value, f.Usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eachName(longName string, fn func(string)) {
|
func eachName(longName string, fn func(string)) {
|
||||||
|
|
@ -73,9 +73,9 @@ func eachName(longName string, fn func(string)) {
|
||||||
|
|
||||||
// called by cli library, grabs variable from environment (if in env)
|
// called by cli library, grabs variable from environment (if in env)
|
||||||
// and adds variable to flag set for parsing.
|
// and adds variable to flag set for parsing.
|
||||||
func (self DirectoryFlag) Apply(set *flag.FlagSet) {
|
func (f DirectoryFlag) Apply(set *flag.FlagSet) {
|
||||||
eachName(self.Name, func(name string) {
|
eachName(f.Name, func(name string) {
|
||||||
set.Var(&self.Value, self.Name, self.Usage)
|
set.Var(&f.Value, f.Name, f.Usage)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,12 +207,12 @@ func prefixedNames(fullName string) (prefixed string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DirectoryFlag) GetName() string {
|
func (f DirectoryFlag) GetName() string {
|
||||||
return self.Name
|
return f.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DirectoryFlag) Set(value string) {
|
func (f *DirectoryFlag) Set(value string) {
|
||||||
self.Value.Value = value
|
f.Value.Value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expands a file path
|
// Expands a file path
|
||||||
|
|
|
||||||
|
|
@ -35,32 +35,32 @@ func NewApi(ch func() *Chequebook) *Api {
|
||||||
return &Api{ch}
|
return &Api{ch}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Balance() (string, error) {
|
func (a *Api) Balance() (string, error) {
|
||||||
ch := self.chequebookf()
|
ch := a.chequebookf()
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
return "", errNoChequebook
|
return "", errNoChequebook
|
||||||
}
|
}
|
||||||
return ch.Balance().String(), nil
|
return ch.Balance().String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) {
|
func (a *Api) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) {
|
||||||
ch := self.chequebookf()
|
ch := a.chequebookf()
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
return nil, errNoChequebook
|
return nil, errNoChequebook
|
||||||
}
|
}
|
||||||
return ch.Issue(beneficiary, amount)
|
return ch.Issue(beneficiary, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Cash(cheque *Cheque) (txhash string, err error) {
|
func (a *Api) Cash(cheque *Cheque) (txhash string, err error) {
|
||||||
ch := self.chequebookf()
|
ch := a.chequebookf()
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
return "", errNoChequebook
|
return "", errNoChequebook
|
||||||
}
|
}
|
||||||
return ch.Cash(cheque)
|
return ch.Cash(cheque)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Deposit(amount *big.Int) (txhash string, err error) {
|
func (a *Api) Deposit(amount *big.Int) (txhash string, err error) {
|
||||||
ch := self.chequebookf()
|
ch := a.chequebookf()
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
return "", errNoChequebook
|
return "", errNoChequebook
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ type Cheque struct {
|
||||||
Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey)
|
Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Cheque) String() string {
|
func (c *Cheque) String() string {
|
||||||
return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", self.Contract.Hex(), self.Beneficiary.Hex(), self.Amount, self.Sig)
|
return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", c.Contract.Hex(), c.Beneficiary.Hex(), c.Amount, c.Sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Params struct {
|
type Params struct {
|
||||||
|
|
@ -109,12 +109,12 @@ type Chequebook struct {
|
||||||
log log.Logger // contextual logger with the contract address embedded
|
log log.Logger // contextual logger with the contract address embedded
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Chequebook) String() string {
|
func (c *Chequebook) String() string {
|
||||||
return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", self.contractAddr.Hex(), self.owner.Hex(), self.balance, self.prvKey.PublicKey)
|
return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", c.contractAddr.Hex(), c.owner.Hex(), c.balance, c.prvKey.PublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChequebook creates a new Chequebook.
|
// NewChequebook creates a new Chequebook.
|
||||||
func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (self *Chequebook, err error) {
|
func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (c *Chequebook, err error) {
|
||||||
balance := new(big.Int)
|
balance := new(big.Int)
|
||||||
sent := make(map[common.Address]*big.Int)
|
sent := make(map[common.Address]*big.Int)
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.Priva
|
||||||
TransactOpts: *transactOpts,
|
TransactOpts: *transactOpts,
|
||||||
}
|
}
|
||||||
|
|
||||||
self = &Chequebook{
|
c = &Chequebook{
|
||||||
prvKey: prvKey,
|
prvKey: prvKey,
|
||||||
balance: balance,
|
balance: balance,
|
||||||
contractAddr: contractAddr,
|
contractAddr: contractAddr,
|
||||||
|
|
@ -142,36 +142,36 @@ func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.Priva
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contractAddr != common.Address{}) {
|
if (contractAddr != common.Address{}) {
|
||||||
self.setBalanceFromBlockChain()
|
c.setBalanceFromBlockChain()
|
||||||
self.log.Trace("New chequebook initialised", "owner", self.owner, "balance", self.balance)
|
c.log.Trace("New chequebook initialised", "owner", c.owner, "balance", c.balance)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Chequebook) setBalanceFromBlockChain() {
|
func (c *Chequebook) setBalanceFromBlockChain() {
|
||||||
balance, err := self.backend.BalanceAt(context.TODO(), self.contractAddr, nil)
|
balance, err := c.backend.BalanceAt(context.TODO(), c.contractAddr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to retrieve chequebook balance", "err", err)
|
log.Error("Failed to retrieve chequebook balance", "err", err)
|
||||||
} else {
|
} else {
|
||||||
self.balance.Set(balance)
|
c.balance.Set(balance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadChequebook loads a chequebook from disk (file path).
|
// LoadChequebook loads a chequebook from disk (file path).
|
||||||
func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (self *Chequebook, err error) {
|
func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (c *Chequebook, err error) {
|
||||||
var data []byte
|
var data []byte
|
||||||
data, err = ioutil.ReadFile(path)
|
data, err = ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self, _ = NewChequebook(path, common.Address{}, prvKey, backend)
|
c, _ = NewChequebook(path, common.Address{}, prvKey, backend)
|
||||||
|
|
||||||
err = json.Unmarshal(data, self)
|
err = json.Unmarshal(data, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if checkBalance {
|
if checkBalance {
|
||||||
self.setBalanceFromBlockChain()
|
c.setBalanceFromBlockChain()
|
||||||
}
|
}
|
||||||
log.Trace("Loaded chequebook from disk", "path", path)
|
log.Trace("Loaded chequebook from disk", "path", path)
|
||||||
|
|
||||||
|
|
@ -187,19 +187,19 @@ type chequebookFile struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON deserialises a chequebook.
|
// UnmarshalJSON deserialises a chequebook.
|
||||||
func (self *Chequebook) UnmarshalJSON(data []byte) error {
|
func (c *Chequebook) UnmarshalJSON(data []byte) error {
|
||||||
var file chequebookFile
|
var file chequebookFile
|
||||||
err := json.Unmarshal(data, &file)
|
err := json.Unmarshal(data, &file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, ok := self.balance.SetString(file.Balance, 10)
|
_, ok := c.balance.SetString(file.Balance, 10)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance)
|
return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance)
|
||||||
}
|
}
|
||||||
self.contractAddr = common.HexToAddress(file.Contract)
|
c.contractAddr = common.HexToAddress(file.Contract)
|
||||||
for addr, sent := range file.Sent {
|
for addr, sent := range file.Sent {
|
||||||
self.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10)
|
c.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent)
|
return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent)
|
||||||
}
|
}
|
||||||
|
|
@ -208,14 +208,14 @@ func (self *Chequebook) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON serialises a chequebook.
|
// MarshalJSON serialises a chequebook.
|
||||||
func (self *Chequebook) MarshalJSON() ([]byte, error) {
|
func (c *Chequebook) MarshalJSON() ([]byte, error) {
|
||||||
var file = &chequebookFile{
|
var file = &chequebookFile{
|
||||||
Balance: self.balance.String(),
|
Balance: c.balance.String(),
|
||||||
Contract: self.contractAddr.Hex(),
|
Contract: c.contractAddr.Hex(),
|
||||||
Owner: self.owner.Hex(),
|
Owner: c.owner.Hex(),
|
||||||
Sent: make(map[string]string),
|
Sent: make(map[string]string),
|
||||||
}
|
}
|
||||||
for addr, sent := range self.sent {
|
for addr, sent := range c.sent {
|
||||||
file.Sent[addr.Hex()] = sent.String()
|
file.Sent[addr.Hex()] = sent.String()
|
||||||
}
|
}
|
||||||
return json.Marshal(file)
|
return json.Marshal(file)
|
||||||
|
|
@ -223,67 +223,67 @@ func (self *Chequebook) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
// Save persists the chequebook on disk, remembering balance, contract address and
|
// Save persists the chequebook on disk, remembering balance, contract address and
|
||||||
// cumulative amount of funds sent for each beneficiary.
|
// cumulative amount of funds sent for each beneficiary.
|
||||||
func (self *Chequebook) Save() (err error) {
|
func (c *Chequebook) Save() (err error) {
|
||||||
data, err := json.MarshalIndent(self, "", " ")
|
data, err := json.MarshalIndent(c, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.log.Trace("Saving chequebook to disk", self.path)
|
c.log.Trace("Saving chequebook to disk", c.path)
|
||||||
|
|
||||||
return ioutil.WriteFile(self.path, data, os.ModePerm)
|
return ioutil.WriteFile(c.path, data, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop quits the autodeposit go routine to terminate
|
// Stop quits the autodeposit go routine to terminate
|
||||||
func (self *Chequebook) Stop() {
|
func (c *Chequebook) Stop() {
|
||||||
defer self.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
self.lock.Lock()
|
c.lock.Lock()
|
||||||
if self.quit != nil {
|
if c.quit != nil {
|
||||||
close(self.quit)
|
close(c.quit)
|
||||||
self.quit = nil
|
c.quit = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue creates a cheque signed by the chequebook owner's private key. The
|
// Issue creates a cheque signed by the chequebook owner's private key. The
|
||||||
// signer commits to a contract (one that they own), a beneficiary and amount.
|
// signer commits to a contract (one that they own), a beneficiary and amount.
|
||||||
func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) {
|
func (c *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) {
|
||||||
defer self.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
self.lock.Lock()
|
c.lock.Lock()
|
||||||
|
|
||||||
if amount.Sign() <= 0 {
|
if amount.Sign() <= 0 {
|
||||||
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
|
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
|
||||||
}
|
}
|
||||||
if self.balance.Cmp(amount) < 0 {
|
if c.balance.Cmp(amount) < 0 {
|
||||||
err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance)
|
err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, c.balance)
|
||||||
} else {
|
} else {
|
||||||
var sig []byte
|
var sig []byte
|
||||||
sent, found := self.sent[beneficiary]
|
sent, found := c.sent[beneficiary]
|
||||||
if !found {
|
if !found {
|
||||||
sent = new(big.Int)
|
sent = new(big.Int)
|
||||||
self.sent[beneficiary] = sent
|
c.sent[beneficiary] = sent
|
||||||
}
|
}
|
||||||
sum := new(big.Int).Set(sent)
|
sum := new(big.Int).Set(sent)
|
||||||
sum.Add(sum, amount)
|
sum.Add(sum, amount)
|
||||||
|
|
||||||
sig, err = crypto.Sign(sigHash(self.contractAddr, beneficiary, sum), self.prvKey)
|
sig, err = crypto.Sign(sigHash(c.contractAddr, beneficiary, sum), c.prvKey)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ch = &Cheque{
|
ch = &Cheque{
|
||||||
Contract: self.contractAddr,
|
Contract: c.contractAddr,
|
||||||
Beneficiary: beneficiary,
|
Beneficiary: beneficiary,
|
||||||
Amount: sum,
|
Amount: sum,
|
||||||
Sig: sig,
|
Sig: sig,
|
||||||
}
|
}
|
||||||
sent.Set(sum)
|
sent.Set(sum)
|
||||||
self.balance.Sub(self.balance, amount) // subtract amount from balance
|
c.balance.Sub(c.balance, amount) // subtract amount from balance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto deposit if threshold is set and balance is less then threshold
|
// auto deposit if threshold is set and balance is less then threshold
|
||||||
// note this is called even if issuing cheque fails
|
// note this is called even if issuing cheque fails
|
||||||
// so we reattempt depositing
|
// so we reattempt depositing
|
||||||
if self.threshold != nil {
|
if c.threshold != nil {
|
||||||
if self.balance.Cmp(self.threshold) < 0 {
|
if c.balance.Cmp(c.threshold) < 0 {
|
||||||
send := new(big.Int).Sub(self.buffer, self.balance)
|
send := new(big.Int).Sub(c.buffer, c.balance)
|
||||||
self.deposit(send)
|
c.deposit(send)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,8 +291,8 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cash is a convenience method to cash any cheque.
|
// Cash is a convenience method to cash any cheque.
|
||||||
func (self *Chequebook) Cash(ch *Cheque) (txhash string, err error) {
|
func (c *Chequebook) Cash(ch *Cheque) (txhash string, err error) {
|
||||||
return ch.Cash(self.session)
|
return ch.Cash(c.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
// data to sign: contract address, beneficiary, cumulative amount of funds ever sent
|
// data to sign: contract address, beneficiary, cumulative amount of funds ever sent
|
||||||
|
|
@ -309,73 +309,73 @@ func sigHash(contract, beneficiary common.Address, sum *big.Int) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Balance returns the current balance of the chequebook.
|
// Balance returns the current balance of the chequebook.
|
||||||
func (self *Chequebook) Balance() *big.Int {
|
func (c *Chequebook) Balance() *big.Int {
|
||||||
defer self.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
self.lock.Lock()
|
c.lock.Lock()
|
||||||
return new(big.Int).Set(self.balance)
|
return new(big.Int).Set(c.balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Owner returns the owner account of the chequebook.
|
// Owner returns the owner account of the chequebook.
|
||||||
func (self *Chequebook) Owner() common.Address {
|
func (c *Chequebook) Owner() common.Address {
|
||||||
return self.owner
|
return c.owner
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address returns the on-chain contract address of the chequebook.
|
// Address returns the on-chain contract address of the chequebook.
|
||||||
func (self *Chequebook) Address() common.Address {
|
func (c *Chequebook) Address() common.Address {
|
||||||
return self.contractAddr
|
return c.contractAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deposit deposits money to the chequebook account.
|
// Deposit deposits money to the chequebook account.
|
||||||
func (self *Chequebook) Deposit(amount *big.Int) (string, error) {
|
func (c *Chequebook) Deposit(amount *big.Int) (string, error) {
|
||||||
defer self.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
self.lock.Lock()
|
c.lock.Lock()
|
||||||
return self.deposit(amount)
|
return c.deposit(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deposit deposits amount to the chequebook account.
|
// deposit deposits amount to the chequebook account.
|
||||||
// The caller must hold self.lock.
|
// The caller must hold c.lock.
|
||||||
func (self *Chequebook) deposit(amount *big.Int) (string, error) {
|
func (c *Chequebook) deposit(amount *big.Int) (string, error) {
|
||||||
// since the amount is variable here, we do not use sessions
|
// since the amount is variable here, we do not use sessions
|
||||||
depositTransactor := bind.NewKeyedTransactor(self.prvKey)
|
depositTransactor := bind.NewKeyedTransactor(c.prvKey)
|
||||||
depositTransactor.Value = amount
|
depositTransactor.Value = amount
|
||||||
chbookRaw := &contract.ChequebookRaw{Contract: self.contract}
|
chbookRaw := &contract.ChequebookRaw{Contract: c.contract}
|
||||||
tx, err := chbookRaw.Transfer(depositTransactor)
|
tx, err := chbookRaw.Transfer(depositTransactor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.log.Warn("Failed to fund chequebook", "amount", amount, "balance", self.balance, "target", self.buffer, "err", err)
|
c.log.Warn("Failed to fund chequebook", "amount", amount, "balance", c.balance, "target", c.buffer, "err", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// assume that transaction is actually successful, we add the amount to balance right away
|
// assume that transaction is actually successful, we add the amount to balance right away
|
||||||
self.balance.Add(self.balance, amount)
|
c.balance.Add(c.balance, amount)
|
||||||
self.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", self.balance, "target", self.buffer)
|
c.log.Trace("Deposited funds to chequebook", "amount", amount, "balance", c.balance, "target", c.buffer)
|
||||||
return tx.Hash().Hex(), nil
|
return tx.Hash().Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoDeposit (re)sets interval time and amount which triggers sending funds to the
|
// AutoDeposit (re)sets interval time and amount which triggers sending funds to the
|
||||||
// chequebook. Contract backend needs to be set if threshold is not less than buffer, then
|
// chequebook. Contract backend needs to be set if threshold is not less than buffer, then
|
||||||
// deposit will be triggered on every new cheque issued.
|
// deposit will be triggered on every new cheque issued.
|
||||||
func (self *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
func (c *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
||||||
defer self.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
self.lock.Lock()
|
c.lock.Lock()
|
||||||
self.threshold = threshold
|
c.threshold = threshold
|
||||||
self.buffer = buffer
|
c.buffer = buffer
|
||||||
self.autoDeposit(interval)
|
c.autoDeposit(interval)
|
||||||
}
|
}
|
||||||
|
|
||||||
// autoDeposit starts a goroutine that periodically sends funds to the chequebook
|
// autoDeposit starts a goroutine that periodically sends funds to the chequebook
|
||||||
// contract caller holds the lock the go routine terminates if Chequebook.quit is closed.
|
// contract caller holds the lock the go routine terminates if Chequebook.quit is closed.
|
||||||
func (self *Chequebook) autoDeposit(interval time.Duration) {
|
func (c *Chequebook) autoDeposit(interval time.Duration) {
|
||||||
if self.quit != nil {
|
if c.quit != nil {
|
||||||
close(self.quit)
|
close(c.quit)
|
||||||
self.quit = nil
|
c.quit = nil
|
||||||
}
|
}
|
||||||
// if threshold >= balance autodeposit after every cheque issued
|
// if threshold >= balance autodeposit after every cheque issued
|
||||||
if interval == time.Duration(0) || self.threshold != nil && self.buffer != nil && self.threshold.Cmp(self.buffer) >= 0 {
|
if interval == time.Duration(0) || c.threshold != nil && c.buffer != nil && c.threshold.Cmp(c.buffer) >= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
self.quit = make(chan bool)
|
c.quit = make(chan bool)
|
||||||
quit := self.quit
|
quit := c.quit
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
|
@ -383,15 +383,15 @@ func (self *Chequebook) autoDeposit(interval time.Duration) {
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
self.lock.Lock()
|
c.lock.Lock()
|
||||||
if self.balance.Cmp(self.buffer) < 0 {
|
if c.balance.Cmp(c.buffer) < 0 {
|
||||||
amount := new(big.Int).Sub(self.buffer, self.balance)
|
amount := new(big.Int).Sub(c.buffer, c.balance)
|
||||||
txhash, err := self.deposit(amount)
|
txhash, err := c.deposit(amount)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
self.txhash = txhash
|
c.txhash = txhash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.lock.Unlock()
|
c.lock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
@ -409,21 +409,21 @@ func NewOutbox(chbook *Chequebook, beneficiary common.Address) *Outbox {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue creates cheque.
|
// Issue creates cheque.
|
||||||
func (self *Outbox) Issue(amount *big.Int) (swap.Promise, error) {
|
func (o *Outbox) Issue(amount *big.Int) (swap.Promise, error) {
|
||||||
return self.chequeBook.Issue(self.beneficiary, amount)
|
return o.chequeBook.Issue(o.beneficiary, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoDeposit enables auto-deposits on the underlying chequebook.
|
// AutoDeposit enables auto-deposits on the underlying chequebook.
|
||||||
func (self *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
func (o *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
||||||
self.chequeBook.AutoDeposit(interval, threshold, buffer)
|
o.chequeBook.AutoDeposit(interval, threshold, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop helps satisfy the swap.OutPayment interface.
|
// Stop helps satisfy the swap.OutPayment interface.
|
||||||
func (self *Outbox) Stop() {}
|
func (o *Outbox) Stop() {}
|
||||||
|
|
||||||
// String implements fmt.Stringer.
|
// String implements fmt.Stringer.
|
||||||
func (self *Outbox) String() string {
|
func (o *Outbox) String() string {
|
||||||
return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.chequeBook.Address().Hex(), self.beneficiary.Hex(), self.chequeBook.Balance())
|
return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", o.chequeBook.Address().Hex(), o.beneficiary.Hex(), o.chequeBook.Balance())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inbox can deposit, verify and cash cheques from a single contract to a single
|
// Inbox can deposit, verify and cash cheques from a single contract to a single
|
||||||
|
|
@ -445,7 +445,7 @@ type Inbox struct {
|
||||||
|
|
||||||
// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated
|
// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated
|
||||||
// from blockchain when first cheque is received.
|
// from blockchain when first cheque is received.
|
||||||
func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (self *Inbox, err error) {
|
func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (*Inbox, error) {
|
||||||
if signer == nil {
|
if signer == nil {
|
||||||
return nil, fmt.Errorf("signer is null")
|
return nil, fmt.Errorf("signer is null")
|
||||||
}
|
}
|
||||||
|
|
@ -461,7 +461,7 @@ func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address
|
||||||
}
|
}
|
||||||
sender := transactOpts.From
|
sender := transactOpts.From
|
||||||
|
|
||||||
self = &Inbox{
|
inbox := &Inbox{
|
||||||
contract: contractAddr,
|
contract: contractAddr,
|
||||||
beneficiary: beneficiary,
|
beneficiary: beneficiary,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
|
|
@ -470,59 +470,59 @@ func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address
|
||||||
cashed: new(big.Int).Set(common.Big0),
|
cashed: new(big.Int).Set(common.Big0),
|
||||||
log: log.New("contract", contractAddr),
|
log: log.New("contract", contractAddr),
|
||||||
}
|
}
|
||||||
self.log.Trace("New chequebook inbox initialized", "beneficiary", self.beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer)))
|
inbox.log.Trace("New chequebook inbox initialized", "beneficiary", beneficiary, "signer", hexutil.Bytes(crypto.FromECDSAPub(signer)))
|
||||||
return
|
return inbox, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Inbox) String() string {
|
func (i *Inbox) String() string {
|
||||||
return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.contract.Hex(), self.beneficiary.Hex(), self.cheque.Amount)
|
return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", i.contract.Hex(), i.beneficiary.Hex(), i.cheque.Amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop quits the autocash goroutine.
|
// Stop quits the autocash goroutine.
|
||||||
func (self *Inbox) Stop() {
|
func (i *Inbox) Stop() {
|
||||||
defer self.lock.Unlock()
|
defer i.lock.Unlock()
|
||||||
self.lock.Lock()
|
i.lock.Lock()
|
||||||
if self.quit != nil {
|
if i.quit != nil {
|
||||||
close(self.quit)
|
close(i.quit)
|
||||||
self.quit = nil
|
i.quit = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cash attempts to cash the current cheque.
|
// Cash attempts to cash the current cheque.
|
||||||
func (self *Inbox) Cash() (txhash string, err error) {
|
func (i *Inbox) Cash() (txhash string, err error) {
|
||||||
if self.cheque != nil {
|
if i.cheque != nil {
|
||||||
txhash, err = self.cheque.Cash(self.session)
|
txhash, err = i.cheque.Cash(i.session)
|
||||||
self.log.Trace("Cashing in chequebook cheque", "amount", self.cheque.Amount, "beneficiary", self.beneficiary)
|
i.log.Trace("Cashing in chequebook cheque", "amount", i.cheque.Amount, "beneficiary", i.beneficiary)
|
||||||
self.cashed = self.cheque.Amount
|
i.cashed = i.cheque.Amount
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoCash (re)sets maximum time and amount which triggers cashing of the last uncashed
|
// AutoCash (re)sets maximum time and amount which triggers cashing of the last uncashed
|
||||||
// cheque if maxUncashed is set to 0, then autocash on receipt.
|
// cheque if maxUncashed is set to 0, then autocash on receipt.
|
||||||
func (self *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) {
|
func (i *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) {
|
||||||
defer self.lock.Unlock()
|
defer i.lock.Unlock()
|
||||||
self.lock.Lock()
|
i.lock.Lock()
|
||||||
self.maxUncashed = maxUncashed
|
i.maxUncashed = maxUncashed
|
||||||
self.autoCash(cashInterval)
|
i.autoCash(cashInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
// autoCash starts a loop that periodically clears the last cheque
|
// autoCash starts a loop that periodically clears the last cheque
|
||||||
// if the peer is trusted. Clearing period could be 24h or a week.
|
// if the peer is trusted. Clearing period could be 24h or a week.
|
||||||
// The caller must hold self.lock.
|
// The caller must hold i.lock.
|
||||||
func (self *Inbox) autoCash(cashInterval time.Duration) {
|
func (i *Inbox) autoCash(cashInterval time.Duration) {
|
||||||
if self.quit != nil {
|
if i.quit != nil {
|
||||||
close(self.quit)
|
close(i.quit)
|
||||||
self.quit = nil
|
i.quit = nil
|
||||||
}
|
}
|
||||||
// if maxUncashed is set to 0, then autocash on receipt
|
// if maxUncashed is set to 0, then autocash on receipt
|
||||||
if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Sign() == 0 {
|
if cashInterval == time.Duration(0) || i.maxUncashed != nil && i.maxUncashed.Sign() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(cashInterval)
|
ticker := time.NewTicker(cashInterval)
|
||||||
self.quit = make(chan bool)
|
i.quit = make(chan bool)
|
||||||
quit := self.quit
|
quit := i.quit
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
|
@ -530,14 +530,14 @@ func (self *Inbox) autoCash(cashInterval time.Duration) {
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
self.lock.Lock()
|
i.lock.Lock()
|
||||||
if self.cheque != nil && self.cheque.Amount.Cmp(self.cashed) != 0 {
|
if i.cheque != nil && i.cheque.Amount.Cmp(i.cashed) != 0 {
|
||||||
txhash, err := self.Cash()
|
txhash, err := i.Cash()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
self.txhash = txhash
|
i.txhash = txhash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.lock.Unlock()
|
i.lock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
@ -545,56 +545,56 @@ func (self *Inbox) autoCash(cashInterval time.Duration) {
|
||||||
|
|
||||||
// Receive is called to deposit the latest cheque to the incoming Inbox.
|
// Receive is called to deposit the latest cheque to the incoming Inbox.
|
||||||
// The given promise must be a *Cheque.
|
// The given promise must be a *Cheque.
|
||||||
func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) {
|
func (i *Inbox) Receive(promise swap.Promise) (*big.Int, error) {
|
||||||
ch := promise.(*Cheque)
|
ch := promise.(*Cheque)
|
||||||
|
|
||||||
defer self.lock.Unlock()
|
defer i.lock.Unlock()
|
||||||
self.lock.Lock()
|
i.lock.Lock()
|
||||||
|
|
||||||
var sum *big.Int
|
var sum *big.Int
|
||||||
if self.cheque == nil {
|
if i.cheque == nil {
|
||||||
// the sum is checked against the blockchain once a cheque is received
|
// the sum is checked against the blockchain once a cheque is received
|
||||||
tally, err := self.session.Sent(self.beneficiary)
|
tally, err := i.session.Sent(i.beneficiary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err)
|
return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err)
|
||||||
}
|
}
|
||||||
sum = tally
|
sum = tally
|
||||||
} else {
|
} else {
|
||||||
sum = self.cheque.Amount
|
sum = i.cheque.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
amount, err := ch.Verify(self.signer, self.contract, self.beneficiary, sum)
|
amount, err := ch.Verify(i.signer, i.contract, i.beneficiary, sum)
|
||||||
var uncashed *big.Int
|
var uncashed *big.Int
|
||||||
if err == nil {
|
if err == nil {
|
||||||
self.cheque = ch
|
i.cheque = ch
|
||||||
|
|
||||||
if self.maxUncashed != nil {
|
if i.maxUncashed != nil {
|
||||||
uncashed = new(big.Int).Sub(ch.Amount, self.cashed)
|
uncashed = new(big.Int).Sub(ch.Amount, i.cashed)
|
||||||
if self.maxUncashed.Cmp(uncashed) < 0 {
|
if i.maxUncashed.Cmp(uncashed) < 0 {
|
||||||
self.Cash()
|
i.Cash()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed)
|
i.log.Trace("Received cheque in chequebook inbox", "amount", amount, "uncashed", uncashed)
|
||||||
}
|
}
|
||||||
|
|
||||||
return amount, err
|
return amount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature.
|
// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature.
|
||||||
func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) {
|
func (c *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) {
|
||||||
log.Trace("Verifying chequebook cheque", "cheque", self, "sum", sum)
|
log.Trace("Verifying chequebook cheque", "cheque", c, "sum", sum)
|
||||||
if sum == nil {
|
if sum == nil {
|
||||||
return nil, fmt.Errorf("invalid amount")
|
return nil, fmt.Errorf("invalid amount")
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.Beneficiary != beneficiary {
|
if c.Beneficiary != beneficiary {
|
||||||
return nil, fmt.Errorf("beneficiary mismatch: %v != %v", self.Beneficiary.Hex(), beneficiary.Hex())
|
return nil, fmt.Errorf("beneficiary mismatch: %v != %v", c.Beneficiary.Hex(), beneficiary.Hex())
|
||||||
}
|
}
|
||||||
if self.Contract != contract {
|
if c.Contract != contract {
|
||||||
return nil, fmt.Errorf("contract mismatch: %v != %v", self.Contract.Hex(), contract.Hex())
|
return nil, fmt.Errorf("contract mismatch: %v != %v", c.Contract.Hex(), contract.Hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
amount := new(big.Int).Set(self.Amount)
|
amount := new(big.Int).Set(c.Amount)
|
||||||
if sum != nil {
|
if sum != nil {
|
||||||
amount.Sub(amount, sum)
|
amount.Sub(amount, sum)
|
||||||
if amount.Sign() <= 0 {
|
if amount.Sign() <= 0 {
|
||||||
|
|
@ -602,7 +602,7 @@ func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary com
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pubKey, err := crypto.SigToPub(sigHash(self.Contract, beneficiary, self.Amount), self.Sig)
|
pubKey, err := crypto.SigToPub(sigHash(c.Contract, beneficiary, c.Amount), c.Sig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid signature: %v", err)
|
return nil, fmt.Errorf("invalid signature: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -621,9 +621,9 @@ func sig2vrs(sig []byte) (v byte, r, s [32]byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cash cashes the cheque by sending an Ethereum transaction.
|
// Cash cashes the cheque by sending an Ethereum transaction.
|
||||||
func (self *Cheque) Cash(session *contract.ChequebookSession) (string, error) {
|
func (c *Cheque) Cash(session *contract.ChequebookSession) (string, error) {
|
||||||
v, r, s := sig2vrs(self.Sig)
|
v, r, s := sig2vrs(c.Sig)
|
||||||
tx, err := session.Cash(self.Beneficiary, self.Amount, v, r, s)
|
tx, err := session.Cash(c.Beneficiary, c.Amount, v, r, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,45 +100,45 @@ func ensNode(name string) common.Hash {
|
||||||
return crypto.Keccak256Hash(parentNode[:], parentLabel[:])
|
return crypto.Keccak256Hash(parentNode[:], parentLabel[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) {
|
func (e *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) {
|
||||||
resolverAddr, err := self.Resolver(node)
|
resolverAddr, err := e.Resolver(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver, err := contract.NewPublicResolver(resolverAddr, self.contractBackend)
|
resolver, err := contract.NewPublicResolver(resolverAddr, e.contractBackend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &contract.PublicResolverSession{
|
return &contract.PublicResolverSession{
|
||||||
Contract: resolver,
|
Contract: resolver,
|
||||||
TransactOpts: self.TransactOpts,
|
TransactOpts: e.TransactOpts,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) {
|
func (e *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) {
|
||||||
registrarAddr, err := self.Owner(node)
|
registrarAddr, err := e.Owner(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
registrar, err := contract.NewFIFSRegistrar(registrarAddr, self.contractBackend)
|
registrar, err := contract.NewFIFSRegistrar(registrarAddr, e.contractBackend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &contract.FIFSRegistrarSession{
|
return &contract.FIFSRegistrarSession{
|
||||||
Contract: registrar,
|
Contract: registrar,
|
||||||
TransactOpts: self.TransactOpts,
|
TransactOpts: e.TransactOpts,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve is a non-transactional call that returns the content hash associated with a name.
|
// Resolve is a non-transactional call that returns the content hash associated with a name.
|
||||||
func (self *ENS) Resolve(name string) (common.Hash, error) {
|
func (e *ENS) Resolve(name string) (common.Hash, error) {
|
||||||
node := ensNode(name)
|
node := ensNode(name)
|
||||||
|
|
||||||
resolver, err := self.getResolver(node)
|
resolver, err := e.getResolver(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -153,26 +153,26 @@ func (self *ENS) Resolve(name string) (common.Hash, error) {
|
||||||
|
|
||||||
// Register registers a new domain name for the caller, making them the owner of the new name.
|
// Register registers a new domain name for the caller, making them the owner of the new name.
|
||||||
// Only works if the registrar for the parent domain implements the FIFS registrar protocol.
|
// Only works if the registrar for the parent domain implements the FIFS registrar protocol.
|
||||||
func (self *ENS) Register(name string) (*types.Transaction, error) {
|
func (e *ENS) Register(name string) (*types.Transaction, error) {
|
||||||
parentNode, label := ensParentNode(name)
|
parentNode, label := ensParentNode(name)
|
||||||
registrar, err := self.getRegistrar(parentNode)
|
registrar, err := e.getRegistrar(parentNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return registrar.Contract.Register(&self.TransactOpts, label, self.TransactOpts.From)
|
return registrar.Contract.Register(&e.TransactOpts, label, e.TransactOpts.From)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetContentHash sets the content hash associated with a name. Only works if the caller
|
// SetContentHash sets the content hash associated with a name. Only works if the caller
|
||||||
// owns the name, and the associated resolver implements a `setContent` function.
|
// owns the name, and the associated resolver implements a `setContent` function.
|
||||||
func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
|
func (e *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
|
||||||
node := ensNode(name)
|
node := ensNode(name)
|
||||||
|
|
||||||
resolver, err := self.getResolver(node)
|
resolver, err := e.getResolver(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := self.TransactOpts
|
opts := e.TransactOpts
|
||||||
opts.GasLimit = 200000
|
opts.GasLimit = 200000
|
||||||
return resolver.Contract.SetContent(&opts, node, hash)
|
return resolver.Contract.SetContent(&opts, node, hash)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,15 +39,15 @@ type Dump struct {
|
||||||
Accounts map[string]DumpAccount `json:"accounts"`
|
Accounts map[string]DumpAccount `json:"accounts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) RawDump() Dump {
|
func (db *StateDB) RawDump() Dump {
|
||||||
dump := Dump{
|
dump := Dump{
|
||||||
Root: fmt.Sprintf("%x", self.trie.Hash()),
|
Root: fmt.Sprintf("%x", db.trie.Hash()),
|
||||||
Accounts: make(map[string]DumpAccount),
|
Accounts: make(map[string]DumpAccount),
|
||||||
}
|
}
|
||||||
|
|
||||||
it := trie.NewIterator(self.trie.NodeIterator(nil))
|
it := trie.NewIterator(db.trie.NodeIterator(nil))
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
addr := self.trie.GetKey(it.Key)
|
addr := db.trie.GetKey(it.Key)
|
||||||
var data Account
|
var data Account
|
||||||
if err := rlp.DecodeBytes(it.Value, &data); err != nil {
|
if err := rlp.DecodeBytes(it.Value, &data); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -59,20 +59,20 @@ func (self *StateDB) RawDump() Dump {
|
||||||
Nonce: data.Nonce,
|
Nonce: data.Nonce,
|
||||||
Root: common.Bytes2Hex(data.Root[:]),
|
Root: common.Bytes2Hex(data.Root[:]),
|
||||||
CodeHash: common.Bytes2Hex(data.CodeHash),
|
CodeHash: common.Bytes2Hex(data.CodeHash),
|
||||||
Code: common.Bytes2Hex(obj.Code(self.db)),
|
Code: common.Bytes2Hex(obj.Code(db.db)),
|
||||||
Storage: make(map[string]string),
|
Storage: make(map[string]string),
|
||||||
}
|
}
|
||||||
storageIt := trie.NewIterator(obj.getTrie(self.db).NodeIterator(nil))
|
storageIt := trie.NewIterator(obj.getTrie(db.db).NodeIterator(nil))
|
||||||
for storageIt.Next() {
|
for storageIt.Next() {
|
||||||
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
account.Storage[common.Bytes2Hex(db.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
||||||
}
|
}
|
||||||
dump.Accounts[common.Bytes2Hex(addr)] = account
|
dump.Accounts[common.Bytes2Hex(addr)] = account
|
||||||
}
|
}
|
||||||
return dump
|
return dump
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Dump() []byte {
|
func (db *StateDB) Dump() []byte {
|
||||||
json, err := json.MarshalIndent(self.RawDump(), "", " ")
|
json, err := json.MarshalIndent(db.RawDump(), "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("dump err", err)
|
fmt.Println("dump err", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,23 +31,23 @@ var emptyCodeHash = crypto.Keccak256(nil)
|
||||||
|
|
||||||
type Code []byte
|
type Code []byte
|
||||||
|
|
||||||
func (self Code) String() string {
|
func (c Code) String() string {
|
||||||
return string(self) //strings.Join(Disassemble(self), " ")
|
return string(c) //strings.Join(Disassemble(c), " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Storage map[common.Hash]common.Hash
|
type Storage map[common.Hash]common.Hash
|
||||||
|
|
||||||
func (self Storage) String() (str string) {
|
func (s Storage) String() (str string) {
|
||||||
for key, value := range self {
|
for key, value := range s {
|
||||||
str += fmt.Sprintf("%X : %X\n", key, value)
|
str += fmt.Sprintf("%X : %X\n", key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Storage) Copy() Storage {
|
func (s Storage) Copy() Storage {
|
||||||
cpy := make(Storage)
|
cpy := make(Storage)
|
||||||
for key, value := range self {
|
for key, value := range s {
|
||||||
cpy[key] = value
|
cpy[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,14 +126,14 @@ func (c *stateObject) EncodeRLP(w io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setError remembers the first non-nil error it is called with.
|
// setError remembers the first non-nil error it is called with.
|
||||||
func (self *stateObject) setError(err error) {
|
func (object *stateObject) setError(err error) {
|
||||||
if self.dbErr == nil {
|
if object.dbErr == nil {
|
||||||
self.dbErr = err
|
object.dbErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) markSuicided() {
|
func (object *stateObject) markSuicided() {
|
||||||
self.suicided = true
|
object.suicided = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *stateObject) touch() {
|
func (c *stateObject) touch() {
|
||||||
|
|
@ -160,75 +160,75 @@ func (c *stateObject) getTrie(db Database) Trie {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetState returns a value in account storage.
|
// GetState returns a value in account storage.
|
||||||
func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
func (object *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
||||||
value, exists := self.cachedStorage[key]
|
value, exists := object.cachedStorage[key]
|
||||||
if exists {
|
if exists {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
// Load from DB in case it is missing.
|
// Load from DB in case it is missing.
|
||||||
enc, err := self.getTrie(db).TryGet(key[:])
|
enc, err := object.getTrie(db).TryGet(key[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.setError(err)
|
object.setError(err)
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
if len(enc) > 0 {
|
if len(enc) > 0 {
|
||||||
_, content, _, err := rlp.Split(enc)
|
_, content, _, err := rlp.Split(enc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.setError(err)
|
object.setError(err)
|
||||||
}
|
}
|
||||||
value.SetBytes(content)
|
value.SetBytes(content)
|
||||||
}
|
}
|
||||||
self.cachedStorage[key] = value
|
object.cachedStorage[key] = value
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetState updates a value in account storage.
|
// SetState updates a value in account storage.
|
||||||
func (self *stateObject) SetState(db Database, key, value common.Hash) {
|
func (object *stateObject) SetState(db Database, key, value common.Hash) {
|
||||||
self.db.journal.append(storageChange{
|
object.db.journal.append(storageChange{
|
||||||
account: &self.address,
|
account: &object.address,
|
||||||
key: key,
|
key: key,
|
||||||
prevalue: self.GetState(db, key),
|
prevalue: object.GetState(db, key),
|
||||||
})
|
})
|
||||||
self.setState(key, value)
|
object.setState(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) setState(key, value common.Hash) {
|
func (object *stateObject) setState(key, value common.Hash) {
|
||||||
self.cachedStorage[key] = value
|
object.cachedStorage[key] = value
|
||||||
self.dirtyStorage[key] = value
|
object.dirtyStorage[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateTrie writes cached storage modifications into the object's storage trie.
|
// updateTrie writes cached storage modifications into the object's storage trie.
|
||||||
func (self *stateObject) updateTrie(db Database) Trie {
|
func (object *stateObject) updateTrie(db Database) Trie {
|
||||||
tr := self.getTrie(db)
|
tr := object.getTrie(db)
|
||||||
for key, value := range self.dirtyStorage {
|
for key, value := range object.dirtyStorage {
|
||||||
delete(self.dirtyStorage, key)
|
delete(object.dirtyStorage, key)
|
||||||
if (value == common.Hash{}) {
|
if (value == common.Hash{}) {
|
||||||
self.setError(tr.TryDelete(key[:]))
|
object.setError(tr.TryDelete(key[:]))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Encoding []byte cannot fail, ok to ignore the error.
|
// Encoding []byte cannot fail, ok to ignore the error.
|
||||||
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
|
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
|
||||||
self.setError(tr.TryUpdate(key[:], v))
|
object.setError(tr.TryUpdate(key[:], v))
|
||||||
}
|
}
|
||||||
return tr
|
return tr
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRoot sets the trie root to the current root hash of
|
// UpdateRoot sets the trie root to the current root hash of
|
||||||
func (self *stateObject) updateRoot(db Database) {
|
func (object *stateObject) updateRoot(db Database) {
|
||||||
self.updateTrie(db)
|
object.updateTrie(db)
|
||||||
self.data.Root = self.trie.Hash()
|
object.data.Root = object.trie.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitTrie the storage trie of the object to dwb.
|
// CommitTrie the storage trie of the object to dwb.
|
||||||
// This updates the trie root.
|
// This updates the trie root.
|
||||||
func (self *stateObject) CommitTrie(db Database) error {
|
func (object *stateObject) CommitTrie(db Database) error {
|
||||||
self.updateTrie(db)
|
object.updateTrie(db)
|
||||||
if self.dbErr != nil {
|
if object.dbErr != nil {
|
||||||
return self.dbErr
|
return object.dbErr
|
||||||
}
|
}
|
||||||
root, err := self.trie.Commit(nil)
|
root, err := object.trie.Commit(nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
self.data.Root = root
|
object.data.Root = root
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -257,32 +257,32 @@ func (c *stateObject) SubBalance(amount *big.Int) {
|
||||||
c.SetBalance(new(big.Int).Sub(c.Balance(), amount))
|
c.SetBalance(new(big.Int).Sub(c.Balance(), amount))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) SetBalance(amount *big.Int) {
|
func (object *stateObject) SetBalance(amount *big.Int) {
|
||||||
self.db.journal.append(balanceChange{
|
object.db.journal.append(balanceChange{
|
||||||
account: &self.address,
|
account: &object.address,
|
||||||
prev: new(big.Int).Set(self.data.Balance),
|
prev: new(big.Int).Set(object.data.Balance),
|
||||||
})
|
})
|
||||||
self.setBalance(amount)
|
object.setBalance(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) setBalance(amount *big.Int) {
|
func (object *stateObject) setBalance(amount *big.Int) {
|
||||||
self.data.Balance = amount
|
object.data.Balance = amount
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||||
func (c *stateObject) ReturnGas(gas *big.Int) {}
|
func (c *stateObject) ReturnGas(gas *big.Int) {}
|
||||||
|
|
||||||
func (self *stateObject) deepCopy(db *StateDB) *stateObject {
|
func (object *stateObject) deepCopy(db *StateDB) *stateObject {
|
||||||
stateObject := newObject(db, self.address, self.data)
|
stateObject := newObject(db, object.address, object.data)
|
||||||
if self.trie != nil {
|
if object.trie != nil {
|
||||||
stateObject.trie = db.db.CopyTrie(self.trie)
|
stateObject.trie = db.db.CopyTrie(object.trie)
|
||||||
}
|
}
|
||||||
stateObject.code = self.code
|
stateObject.code = object.code
|
||||||
stateObject.dirtyStorage = self.dirtyStorage.Copy()
|
stateObject.dirtyStorage = object.dirtyStorage.Copy()
|
||||||
stateObject.cachedStorage = self.dirtyStorage.Copy()
|
stateObject.cachedStorage = object.dirtyStorage.Copy()
|
||||||
stateObject.suicided = self.suicided
|
stateObject.suicided = object.suicided
|
||||||
stateObject.dirtyCode = self.dirtyCode
|
stateObject.dirtyCode = object.dirtyCode
|
||||||
stateObject.deleted = self.deleted
|
stateObject.deleted = object.deleted
|
||||||
return stateObject
|
return stateObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,64 +296,64 @@ func (c *stateObject) Address() common.Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code returns the contract code associated with this object, if any.
|
// Code returns the contract code associated with this object, if any.
|
||||||
func (self *stateObject) Code(db Database) []byte {
|
func (object *stateObject) Code(db Database) []byte {
|
||||||
if self.code != nil {
|
if object.code != nil {
|
||||||
return self.code
|
return object.code
|
||||||
}
|
}
|
||||||
if bytes.Equal(self.CodeHash(), emptyCodeHash) {
|
if bytes.Equal(object.CodeHash(), emptyCodeHash) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
code, err := db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash()))
|
code, err := db.ContractCode(object.addrHash, common.BytesToHash(object.CodeHash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.setError(fmt.Errorf("can't load code hash %x: %v", self.CodeHash(), err))
|
object.setError(fmt.Errorf("can't load code hash %x: %v", object.CodeHash(), err))
|
||||||
}
|
}
|
||||||
self.code = code
|
object.code = code
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
func (object *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
||||||
prevcode := self.Code(self.db.db)
|
prevcode := object.Code(object.db.db)
|
||||||
self.db.journal.append(codeChange{
|
object.db.journal.append(codeChange{
|
||||||
account: &self.address,
|
account: &object.address,
|
||||||
prevhash: self.CodeHash(),
|
prevhash: object.CodeHash(),
|
||||||
prevcode: prevcode,
|
prevcode: prevcode,
|
||||||
})
|
})
|
||||||
self.setCode(codeHash, code)
|
object.setCode(codeHash, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) setCode(codeHash common.Hash, code []byte) {
|
func (object *stateObject) setCode(codeHash common.Hash, code []byte) {
|
||||||
self.code = code
|
object.code = code
|
||||||
self.data.CodeHash = codeHash[:]
|
object.data.CodeHash = codeHash[:]
|
||||||
self.dirtyCode = true
|
object.dirtyCode = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) SetNonce(nonce uint64) {
|
func (object *stateObject) SetNonce(nonce uint64) {
|
||||||
self.db.journal.append(nonceChange{
|
object.db.journal.append(nonceChange{
|
||||||
account: &self.address,
|
account: &object.address,
|
||||||
prev: self.data.Nonce,
|
prev: object.data.Nonce,
|
||||||
})
|
})
|
||||||
self.setNonce(nonce)
|
object.setNonce(nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) setNonce(nonce uint64) {
|
func (object *stateObject) setNonce(nonce uint64) {
|
||||||
self.data.Nonce = nonce
|
object.data.Nonce = nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) CodeHash() []byte {
|
func (object *stateObject) CodeHash() []byte {
|
||||||
return self.data.CodeHash
|
return object.data.CodeHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) Balance() *big.Int {
|
func (object *stateObject) Balance() *big.Int {
|
||||||
return self.data.Balance
|
return object.data.Balance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stateObject) Nonce() uint64 {
|
func (object *stateObject) Nonce() uint64 {
|
||||||
return self.data.Nonce
|
return object.data.Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never called, but must be present to allow stateObject to be used
|
// Never called, but must be present to allow stateObject to be used
|
||||||
// as a vm.Account interface that also satisfies the vm.ContractRef
|
// as a vm.Account interface that also satisfies the vm.ContractRef
|
||||||
// interface. Interfaces are awesome.
|
// interface. Interfaces are awesome.
|
||||||
func (self *stateObject) Value() *big.Int {
|
func (object *stateObject) Value() *big.Int {
|
||||||
panic("Value on stateObject should never be called")
|
panic("Value on stateObject should never be called")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,103 +101,103 @@ func New(root common.Hash, db Database) (*StateDB, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setError remembers the first non-nil error it is called with.
|
// setError remembers the first non-nil error it is called with.
|
||||||
func (self *StateDB) setError(err error) {
|
func (db *StateDB) setError(err error) {
|
||||||
if self.dbErr == nil {
|
if db.dbErr == nil {
|
||||||
self.dbErr = err
|
db.dbErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Error() error {
|
func (db *StateDB) Error() error {
|
||||||
return self.dbErr
|
return db.dbErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears out all ephemeral state objects from the state db, but keeps
|
// Reset clears out all ephemeral state objects from the state db, but keeps
|
||||||
// the underlying state trie to avoid reloading data for the next operations.
|
// the underlying state trie to avoid reloading data for the next operations.
|
||||||
func (self *StateDB) Reset(root common.Hash) error {
|
func (db *StateDB) Reset(root common.Hash) error {
|
||||||
tr, err := self.db.OpenTrie(root)
|
tr, err := db.db.OpenTrie(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.trie = tr
|
db.trie = tr
|
||||||
self.stateObjects = make(map[common.Address]*stateObject)
|
db.stateObjects = make(map[common.Address]*stateObject)
|
||||||
self.stateObjectsDirty = make(map[common.Address]struct{})
|
db.stateObjectsDirty = make(map[common.Address]struct{})
|
||||||
self.thash = common.Hash{}
|
db.thash = common.Hash{}
|
||||||
self.bhash = common.Hash{}
|
db.bhash = common.Hash{}
|
||||||
self.txIndex = 0
|
db.txIndex = 0
|
||||||
self.logs = make(map[common.Hash][]*types.Log)
|
db.logs = make(map[common.Hash][]*types.Log)
|
||||||
self.logSize = 0
|
db.logSize = 0
|
||||||
self.preimages = make(map[common.Hash][]byte)
|
db.preimages = make(map[common.Hash][]byte)
|
||||||
self.clearJournalAndRefund()
|
db.clearJournalAndRefund()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) AddLog(log *types.Log) {
|
func (db *StateDB) AddLog(log *types.Log) {
|
||||||
self.journal.append(addLogChange{txhash: self.thash})
|
db.journal.append(addLogChange{txhash: db.thash})
|
||||||
|
|
||||||
log.TxHash = self.thash
|
log.TxHash = db.thash
|
||||||
log.BlockHash = self.bhash
|
log.BlockHash = db.bhash
|
||||||
log.TxIndex = uint(self.txIndex)
|
log.TxIndex = uint(db.txIndex)
|
||||||
log.Index = self.logSize
|
log.Index = db.logSize
|
||||||
self.logs[self.thash] = append(self.logs[self.thash], log)
|
db.logs[db.thash] = append(db.logs[db.thash], log)
|
||||||
self.logSize++
|
db.logSize++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetLogs(hash common.Hash) []*types.Log {
|
func (db *StateDB) GetLogs(hash common.Hash) []*types.Log {
|
||||||
return self.logs[hash]
|
return db.logs[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Logs() []*types.Log {
|
func (db *StateDB) Logs() []*types.Log {
|
||||||
var logs []*types.Log
|
var logs []*types.Log
|
||||||
for _, lgs := range self.logs {
|
for _, lgs := range db.logs {
|
||||||
logs = append(logs, lgs...)
|
logs = append(logs, lgs...)
|
||||||
}
|
}
|
||||||
return logs
|
return logs
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPreimage records a SHA3 preimage seen by the VM.
|
// AddPreimage records a SHA3 preimage seen by the VM.
|
||||||
func (self *StateDB) AddPreimage(hash common.Hash, preimage []byte) {
|
func (db *StateDB) AddPreimage(hash common.Hash, preimage []byte) {
|
||||||
if _, ok := self.preimages[hash]; !ok {
|
if _, ok := db.preimages[hash]; !ok {
|
||||||
self.journal.append(addPreimageChange{hash: hash})
|
db.journal.append(addPreimageChange{hash: hash})
|
||||||
pi := make([]byte, len(preimage))
|
pi := make([]byte, len(preimage))
|
||||||
copy(pi, preimage)
|
copy(pi, preimage)
|
||||||
self.preimages[hash] = pi
|
db.preimages[hash] = pi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preimages returns a list of SHA3 preimages that have been submitted.
|
// Preimages returns a list of SHA3 preimages that have been submitted.
|
||||||
func (self *StateDB) Preimages() map[common.Hash][]byte {
|
func (db *StateDB) Preimages() map[common.Hash][]byte {
|
||||||
return self.preimages
|
return db.preimages
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) AddRefund(gas uint64) {
|
func (db *StateDB) AddRefund(gas uint64) {
|
||||||
self.journal.append(refundChange{prev: self.refund})
|
db.journal.append(refundChange{prev: db.refund})
|
||||||
self.refund += gas
|
db.refund += gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exist reports whether the given account address exists in the state.
|
// Exist reports whether the given account address exists in the state.
|
||||||
// Notably this also returns true for suicided accounts.
|
// Notably this also returns true for suicided accounts.
|
||||||
func (self *StateDB) Exist(addr common.Address) bool {
|
func (db *StateDB) Exist(addr common.Address) bool {
|
||||||
return self.getStateObject(addr) != nil
|
return db.getStateObject(addr) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty returns whether the state object is either non-existent
|
// Empty returns whether the state object is either non-existent
|
||||||
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
||||||
func (self *StateDB) Empty(addr common.Address) bool {
|
func (db *StateDB) Empty(addr common.Address) bool {
|
||||||
so := self.getStateObject(addr)
|
so := db.getStateObject(addr)
|
||||||
return so == nil || so.empty()
|
return so == nil || so.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the balance from the given address or 0 if object not found
|
// Retrieve the balance from the given address or 0 if object not found
|
||||||
func (self *StateDB) GetBalance(addr common.Address) *big.Int {
|
func (db *StateDB) GetBalance(addr common.Address) *big.Int {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Balance()
|
return stateObject.Balance()
|
||||||
}
|
}
|
||||||
return common.Big0
|
return common.Big0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetNonce(addr common.Address) uint64 {
|
func (db *StateDB) GetNonce(addr common.Address) uint64 {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Nonce()
|
return stateObject.Nonce()
|
||||||
}
|
}
|
||||||
|
|
@ -205,63 +205,63 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetCode(addr common.Address) []byte {
|
func (db *StateDB) GetCode(addr common.Address) []byte {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Code(self.db)
|
return stateObject.Code(db.db)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetCodeSize(addr common.Address) int {
|
func (db *StateDB) GetCodeSize(addr common.Address) int {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if stateObject.code != nil {
|
if stateObject.code != nil {
|
||||||
return len(stateObject.code)
|
return len(stateObject.code)
|
||||||
}
|
}
|
||||||
size, err := self.db.ContractCodeSize(stateObject.addrHash, common.BytesToHash(stateObject.CodeHash()))
|
size, err := db.db.ContractCodeSize(stateObject.addrHash, common.BytesToHash(stateObject.CodeHash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.setError(err)
|
db.setError(err)
|
||||||
}
|
}
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
func (db *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
return common.BytesToHash(stateObject.CodeHash())
|
return common.BytesToHash(stateObject.CodeHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash {
|
func (db *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.GetState(self.db, bhash)
|
return stateObject.GetState(db.db, bhash)
|
||||||
}
|
}
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database retrieves the low level database supporting the lower level trie ops.
|
// Database retrieves the low level database supporting the lower level trie ops.
|
||||||
func (self *StateDB) Database() Database {
|
func (db *StateDB) Database() Database {
|
||||||
return self.db
|
return db.db
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageTrie returns the storage trie of an account.
|
// StorageTrie returns the storage trie of an account.
|
||||||
// The return value is a copy and is nil for non-existent accounts.
|
// The return value is a copy and is nil for non-existent accounts.
|
||||||
func (self *StateDB) StorageTrie(addr common.Address) Trie {
|
func (db *StateDB) StorageTrie(addr common.Address) Trie {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
cpy := stateObject.deepCopy(self)
|
cpy := stateObject.deepCopy(db)
|
||||||
return cpy.updateTrie(self.db)
|
return cpy.updateTrie(db.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) HasSuicided(addr common.Address) bool {
|
func (db *StateDB) HasSuicided(addr common.Address) bool {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.suicided
|
return stateObject.suicided
|
||||||
}
|
}
|
||||||
|
|
@ -273,46 +273,46 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// AddBalance adds amount to the account associated with addr.
|
// AddBalance adds amount to the account associated with addr.
|
||||||
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
func (db *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := db.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.AddBalance(amount)
|
stateObject.AddBalance(amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubBalance subtracts amount from the account associated with addr.
|
// SubBalance subtracts amount from the account associated with addr.
|
||||||
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
func (db *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := db.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SubBalance(amount)
|
stateObject.SubBalance(amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
func (db *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := db.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetBalance(amount)
|
stateObject.SetBalance(amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
func (db *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := db.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetNonce(nonce)
|
stateObject.SetNonce(nonce)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetCode(addr common.Address, code []byte) {
|
func (db *StateDB) SetCode(addr common.Address, code []byte) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := db.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetCode(crypto.Keccak256Hash(code), code)
|
stateObject.SetCode(crypto.Keccak256Hash(code), code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetState(addr common.Address, key, value common.Hash) {
|
func (db *StateDB) SetState(addr common.Address, key, value common.Hash) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := db.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetState(self.db, key, value)
|
stateObject.SetState(db.db, key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -321,12 +321,12 @@ func (self *StateDB) SetState(addr common.Address, key, value common.Hash) {
|
||||||
//
|
//
|
||||||
// The account's state object is still available until the state is committed,
|
// The account's state object is still available until the state is committed,
|
||||||
// getStateObject will return a non-nil account after Suicide.
|
// getStateObject will return a non-nil account after Suicide.
|
||||||
func (self *StateDB) Suicide(addr common.Address) bool {
|
func (db *StateDB) Suicide(addr common.Address) bool {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
self.journal.append(suicideChange{
|
db.journal.append(suicideChange{
|
||||||
account: &addr,
|
account: &addr,
|
||||||
prev: stateObject.suicided,
|
prev: stateObject.suicided,
|
||||||
prevbalance: new(big.Int).Set(stateObject.Balance()),
|
prevbalance: new(big.Int).Set(stateObject.Balance()),
|
||||||
|
|
@ -342,26 +342,26 @@ func (self *StateDB) Suicide(addr common.Address) bool {
|
||||||
//
|
//
|
||||||
|
|
||||||
// updateStateObject writes the given object to the trie.
|
// updateStateObject writes the given object to the trie.
|
||||||
func (self *StateDB) updateStateObject(stateObject *stateObject) {
|
func (db *StateDB) updateStateObject(stateObject *stateObject) {
|
||||||
addr := stateObject.Address()
|
addr := stateObject.Address()
|
||||||
data, err := rlp.EncodeToBytes(stateObject)
|
data, err := rlp.EncodeToBytes(stateObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
|
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
|
||||||
}
|
}
|
||||||
self.setError(self.trie.TryUpdate(addr[:], data))
|
db.setError(db.trie.TryUpdate(addr[:], data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteStateObject removes the given object from the state trie.
|
// deleteStateObject removes the given object from the state trie.
|
||||||
func (self *StateDB) deleteStateObject(stateObject *stateObject) {
|
func (db *StateDB) deleteStateObject(stateObject *stateObject) {
|
||||||
stateObject.deleted = true
|
stateObject.deleted = true
|
||||||
addr := stateObject.Address()
|
addr := stateObject.Address()
|
||||||
self.setError(self.trie.TryDelete(addr[:]))
|
db.setError(db.trie.TryDelete(addr[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object given by the address. Returns nil if not found.
|
// Retrieve a state object given by the address. Returns nil if not found.
|
||||||
func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
|
func (db *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
|
||||||
// Prefer 'live' objects.
|
// Prefer 'live' objects.
|
||||||
if obj := self.stateObjects[addr]; obj != nil {
|
if obj := db.stateObjects[addr]; obj != nil {
|
||||||
if obj.deleted {
|
if obj.deleted {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -369,9 +369,9 @@ func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObje
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the object from the database.
|
// Load the object from the database.
|
||||||
enc, err := self.trie.TryGet(addr[:])
|
enc, err := db.trie.TryGet(addr[:])
|
||||||
if len(enc) == 0 {
|
if len(enc) == 0 {
|
||||||
self.setError(err)
|
db.setError(err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var data Account
|
var data Account
|
||||||
|
|
@ -380,36 +380,36 @@ func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObje
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Insert into the live set.
|
// Insert into the live set.
|
||||||
obj := newObject(self, addr, data)
|
obj := newObject(db, addr, data)
|
||||||
self.setStateObject(obj)
|
db.setStateObject(obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) setStateObject(object *stateObject) {
|
func (db *StateDB) setStateObject(object *stateObject) {
|
||||||
self.stateObjects[object.Address()] = object
|
db.stateObjects[object.Address()] = object
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object or create a new state object if nil.
|
// Retrieve a state object or create a new state object if nil.
|
||||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
func (db *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
||||||
stateObject := self.getStateObject(addr)
|
stateObject := db.getStateObject(addr)
|
||||||
if stateObject == nil || stateObject.deleted {
|
if stateObject == nil || stateObject.deleted {
|
||||||
stateObject, _ = self.createObject(addr)
|
stateObject, _ = db.createObject(addr)
|
||||||
}
|
}
|
||||||
return stateObject
|
return stateObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// createObject creates a new state object. If there is an existing account with
|
// createObject creates a new state object. If there is an existing account with
|
||||||
// the given address, it is overwritten and returned as the second return value.
|
// the given address, it is overwritten and returned as the second return value.
|
||||||
func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
func (db *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
||||||
prev = self.getStateObject(addr)
|
prev = db.getStateObject(addr)
|
||||||
newobj = newObject(self, addr, Account{})
|
newobj = newObject(db, addr, Account{})
|
||||||
newobj.setNonce(0) // sets the object to dirty
|
newobj.setNonce(0) // sets the object to dirty
|
||||||
if prev == nil {
|
if prev == nil {
|
||||||
self.journal.append(createObjectChange{account: &addr})
|
db.journal.append(createObjectChange{account: &addr})
|
||||||
} else {
|
} else {
|
||||||
self.journal.append(resetObjectChange{prev: prev})
|
db.journal.append(resetObjectChange{prev: prev})
|
||||||
}
|
}
|
||||||
self.setStateObject(newobj)
|
db.setStateObject(newobj)
|
||||||
return newobj, prev
|
return newobj, prev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,8 +423,8 @@ func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObjec
|
||||||
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
||||||
//
|
//
|
||||||
// Carrying over the balance ensures that Ether doesn't disappear.
|
// Carrying over the balance ensures that Ether doesn't disappear.
|
||||||
func (self *StateDB) CreateAccount(addr common.Address) {
|
func (db *StateDB) CreateAccount(addr common.Address) {
|
||||||
new, prev := self.createObject(addr)
|
new, prev := db.createObject(addr)
|
||||||
if prev != nil {
|
if prev != nil {
|
||||||
new.setBalance(prev.data.Balance)
|
new.setBalance(prev.data.Balance)
|
||||||
}
|
}
|
||||||
|
|
@ -453,29 +453,29 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
|
||||||
|
|
||||||
// Copy creates a deep, independent copy of the state.
|
// Copy creates a deep, independent copy of the state.
|
||||||
// Snapshots of the copied state cannot be applied to the copy.
|
// Snapshots of the copied state cannot be applied to the copy.
|
||||||
func (self *StateDB) Copy() *StateDB {
|
func (db *StateDB) Copy() *StateDB {
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
|
|
||||||
// Copy all the basic fields, initialize the memory ones
|
// Copy all the basic fields, initialize the memory ones
|
||||||
state := &StateDB{
|
state := &StateDB{
|
||||||
db: self.db,
|
db: db.db,
|
||||||
trie: self.db.CopyTrie(self.trie),
|
trie: db.db.CopyTrie(db.trie),
|
||||||
stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)),
|
stateObjects: make(map[common.Address]*stateObject, len(db.journal.dirties)),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)),
|
stateObjectsDirty: make(map[common.Address]struct{}, len(db.journal.dirties)),
|
||||||
refund: self.refund,
|
refund: db.refund,
|
||||||
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
logs: make(map[common.Hash][]*types.Log, len(db.logs)),
|
||||||
logSize: self.logSize,
|
logSize: db.logSize,
|
||||||
preimages: make(map[common.Hash][]byte),
|
preimages: make(map[common.Hash][]byte),
|
||||||
journal: newJournal(),
|
journal: newJournal(),
|
||||||
}
|
}
|
||||||
// Copy the dirty states, logs, and preimages
|
// Copy the dirty states, logs, and preimages
|
||||||
for addr := range self.journal.dirties {
|
for addr := range db.journal.dirties {
|
||||||
// As documented [here](https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527),
|
// As documented [here](https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527),
|
||||||
// and in the Finalise-method, there is a case where an object is in the journal but not
|
// and in the Finalise-method, there is a case where an object is in the journal but not
|
||||||
// in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for
|
// in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for
|
||||||
// nil
|
// nil
|
||||||
if object, exist := self.stateObjects[addr]; exist {
|
if object, exist := db.stateObjects[addr]; exist {
|
||||||
state.stateObjects[addr] = object.deepCopy(state)
|
state.stateObjects[addr] = object.deepCopy(state)
|
||||||
state.stateObjectsDirty[addr] = struct{}{}
|
state.stateObjectsDirty[addr] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
@ -483,53 +483,53 @@ func (self *StateDB) Copy() *StateDB {
|
||||||
// Above, we don't copy the actual journal. This means that if the copy is copied, the
|
// Above, we don't copy the actual journal. This means that if the copy is copied, the
|
||||||
// loop above will be a no-op, since the copy's journal is empty.
|
// loop above will be a no-op, since the copy's journal is empty.
|
||||||
// Thus, here we iterate over stateObjects, to enable copies of copies
|
// Thus, here we iterate over stateObjects, to enable copies of copies
|
||||||
for addr := range self.stateObjectsDirty {
|
for addr := range db.stateObjectsDirty {
|
||||||
if _, exist := state.stateObjects[addr]; !exist {
|
if _, exist := state.stateObjects[addr]; !exist {
|
||||||
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
|
state.stateObjects[addr] = db.stateObjects[addr].deepCopy(state)
|
||||||
state.stateObjectsDirty[addr] = struct{}{}
|
state.stateObjectsDirty[addr] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for hash, logs := range self.logs {
|
for hash, logs := range db.logs {
|
||||||
state.logs[hash] = make([]*types.Log, len(logs))
|
state.logs[hash] = make([]*types.Log, len(logs))
|
||||||
copy(state.logs[hash], logs)
|
copy(state.logs[hash], logs)
|
||||||
}
|
}
|
||||||
for hash, preimage := range self.preimages {
|
for hash, preimage := range db.preimages {
|
||||||
state.preimages[hash] = preimage
|
state.preimages[hash] = preimage
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns an identifier for the current revision of the state.
|
// Snapshot returns an identifier for the current revision of the state.
|
||||||
func (self *StateDB) Snapshot() int {
|
func (db *StateDB) Snapshot() int {
|
||||||
id := self.nextRevisionId
|
id := db.nextRevisionId
|
||||||
self.nextRevisionId++
|
db.nextRevisionId++
|
||||||
self.validRevisions = append(self.validRevisions, revision{id, self.journal.length()})
|
db.validRevisions = append(db.validRevisions, revision{id, db.journal.length()})
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevertToSnapshot reverts all state changes made since the given revision.
|
// RevertToSnapshot reverts all state changes made since the given revision.
|
||||||
func (self *StateDB) RevertToSnapshot(revid int) {
|
func (db *StateDB) RevertToSnapshot(revid int) {
|
||||||
// Find the snapshot in the stack of valid snapshots.
|
// Find the snapshot in the stack of valid snapshots.
|
||||||
idx := sort.Search(len(self.validRevisions), func(i int) bool {
|
idx := sort.Search(len(db.validRevisions), func(i int) bool {
|
||||||
return self.validRevisions[i].id >= revid
|
return db.validRevisions[i].id >= revid
|
||||||
})
|
})
|
||||||
if idx == len(self.validRevisions) || self.validRevisions[idx].id != revid {
|
if idx == len(db.validRevisions) || db.validRevisions[idx].id != revid {
|
||||||
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
||||||
}
|
}
|
||||||
snapshot := self.validRevisions[idx].journalIndex
|
snapshot := db.validRevisions[idx].journalIndex
|
||||||
|
|
||||||
// Replay the journal to undo changes and remove invalidated snapshots
|
// Replay the journal to undo changes and remove invalidated snapshots
|
||||||
self.journal.revert(self, snapshot)
|
db.journal.revert(db, snapshot)
|
||||||
self.validRevisions = self.validRevisions[:idx]
|
db.validRevisions = db.validRevisions[:idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRefund returns the current value of the refund counter.
|
// GetRefund returns the current value of the refund counter.
|
||||||
func (self *StateDB) GetRefund() uint64 {
|
func (db *StateDB) GetRefund() uint64 {
|
||||||
return self.refund
|
return db.refund
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalise finalises the state by removing the self destructed objects
|
// Finalise finalises the state by removing the db destructed objects
|
||||||
// and clears the journal as well as the refunds.
|
// and clears the journal as well as the refunds.
|
||||||
func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||||
for addr := range s.journal.dirties {
|
for addr := range s.journal.dirties {
|
||||||
|
|
@ -566,10 +566,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
|
|
||||||
// Prepare sets the current transaction hash and index and block hash which is
|
// Prepare sets the current transaction hash and index and block hash which is
|
||||||
// used when the EVM emits new state logs.
|
// used when the EVM emits new state logs.
|
||||||
func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) {
|
func (db *StateDB) Prepare(thash, bhash common.Hash, ti int) {
|
||||||
self.thash = thash
|
db.thash = thash
|
||||||
self.bhash = bhash
|
db.bhash = bhash
|
||||||
self.txIndex = ti
|
db.txIndex = ti
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) clearJournalAndRefund() {
|
func (s *StateDB) clearJournalAndRefund() {
|
||||||
|
|
|
||||||
|
|
@ -392,10 +392,10 @@ type Blocks []*Block
|
||||||
|
|
||||||
type BlockBy func(b1, b2 *Block) bool
|
type BlockBy func(b1, b2 *Block) bool
|
||||||
|
|
||||||
func (self BlockBy) Sort(blocks Blocks) {
|
func (by BlockBy) Sort(blocks Blocks) {
|
||||||
bs := blockSorter{
|
bs := blockSorter{
|
||||||
blocks: blocks,
|
blocks: blocks,
|
||||||
by: self,
|
by: by,
|
||||||
}
|
}
|
||||||
sort.Sort(bs)
|
sort.Sort(bs)
|
||||||
}
|
}
|
||||||
|
|
@ -405,10 +405,10 @@ type blockSorter struct {
|
||||||
by func(b1, b2 *Block) bool
|
by func(b1, b2 *Block) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self blockSorter) Len() int { return len(self.blocks) }
|
func (b blockSorter) Len() int { return len(b.blocks) }
|
||||||
func (self blockSorter) Swap(i, j int) {
|
func (b blockSorter) Swap(i, j int) {
|
||||||
self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i]
|
b.blocks[i], b.blocks[j] = b.blocks[j], b.blocks[i]
|
||||||
}
|
}
|
||||||
func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
|
func (b blockSorter) Less(i, j int) bool { return b.by(b.blocks[i], b.blocks[j]) }
|
||||||
|
|
||||||
func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 }
|
func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 }
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,18 @@ type Generic struct {
|
||||||
Fn func(data interface{})
|
Fn func(data interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// self = registered, f = incoming
|
// g = registered, f = incoming
|
||||||
func (self Generic) Compare(f Filter) bool {
|
func (g Generic) Compare(f Filter) bool {
|
||||||
var strMatch, dataMatch = true, true
|
var strMatch, dataMatch = true, true
|
||||||
|
|
||||||
filter := f.(Generic)
|
filter := f.(Generic)
|
||||||
if (len(self.Str1) > 0 && filter.Str1 != self.Str1) ||
|
if (len(g.Str1) > 0 && filter.Str1 != g.Str1) ||
|
||||||
(len(self.Str2) > 0 && filter.Str2 != self.Str2) ||
|
(len(g.Str2) > 0 && filter.Str2 != g.Str2) ||
|
||||||
(len(self.Str3) > 0 && filter.Str3 != self.Str3) {
|
(len(g.Str3) > 0 && filter.Str3 != g.Str3) {
|
||||||
strMatch = false
|
strMatch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range self.Data {
|
for k := range g.Data {
|
||||||
if _, ok := filter.Data[k]; !ok {
|
if _, ok := filter.Data[k]; !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +43,6 @@ func (self Generic) Compare(f Filter) bool {
|
||||||
return strMatch && dataMatch
|
return strMatch && dataMatch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self Generic) Trigger(data interface{}) {
|
func (g Generic) Trigger(data interface{}) {
|
||||||
self.Fn(data)
|
g.Fn(data)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,16 +89,16 @@ func NewClientManager(rcTarget, maxSimReq, maxRcSum uint64) *ClientManager {
|
||||||
return cm
|
return cm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) Stop() {
|
func (cm *ClientManager) Stop() {
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer cm.lock.Unlock()
|
||||||
|
|
||||||
// signal any waiting accept routines to return false
|
// signal any waiting accept routines to return false
|
||||||
self.nodes = make(map[*cmNode]struct{})
|
cm.nodes = make(map[*cmNode]struct{})
|
||||||
close(self.resumeQueue)
|
close(cm.resumeQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) addNode(cnode *ClientNode) *cmNode {
|
func (cm *ClientManager) addNode(cnode *ClientNode) *cmNode {
|
||||||
time := mclock.Now()
|
time := mclock.Now()
|
||||||
node := &cmNode{
|
node := &cmNode{
|
||||||
node: cnode,
|
node: cnode,
|
||||||
|
|
@ -106,28 +106,28 @@ func (self *ClientManager) addNode(cnode *ClientNode) *cmNode {
|
||||||
finishRecharge: time,
|
finishRecharge: time,
|
||||||
rcWeight: 1,
|
rcWeight: 1,
|
||||||
}
|
}
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer cm.lock.Unlock()
|
||||||
|
|
||||||
self.nodes[node] = struct{}{}
|
cm.nodes[node] = struct{}{}
|
||||||
self.update(mclock.Now())
|
cm.update(mclock.Now())
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) removeNode(node *cmNode) {
|
func (cm *ClientManager) removeNode(node *cmNode) {
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer cm.lock.Unlock()
|
||||||
|
|
||||||
time := mclock.Now()
|
time := mclock.Now()
|
||||||
self.stop(node, time)
|
cm.stop(node, time)
|
||||||
delete(self.nodes, node)
|
delete(cm.nodes, node)
|
||||||
self.update(time)
|
cm.update(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recalc sumWeight
|
// recalc sumWeight
|
||||||
func (self *ClientManager) updateNodes(time mclock.AbsTime) (rce bool) {
|
func (cm *ClientManager) updateNodes(time mclock.AbsTime) (rce bool) {
|
||||||
var sumWeight, rcSum uint64
|
var sumWeight, rcSum uint64
|
||||||
for node := range self.nodes {
|
for node := range cm.nodes {
|
||||||
rc := node.recharging
|
rc := node.recharging
|
||||||
node.update(time)
|
node.update(time)
|
||||||
if rc && !node.recharging {
|
if rc && !node.recharging {
|
||||||
|
|
@ -138,44 +138,44 @@ func (self *ClientManager) updateNodes(time mclock.AbsTime) (rce bool) {
|
||||||
}
|
}
|
||||||
rcSum += uint64(node.rcValue)
|
rcSum += uint64(node.rcValue)
|
||||||
}
|
}
|
||||||
self.sumWeight = sumWeight
|
cm.sumWeight = sumWeight
|
||||||
self.rcSumValue = rcSum
|
cm.rcSumValue = rcSum
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) update(time mclock.AbsTime) {
|
func (cm *ClientManager) update(time mclock.AbsTime) {
|
||||||
for {
|
for {
|
||||||
firstTime := time
|
firstTime := time
|
||||||
for node := range self.nodes {
|
for node := range cm.nodes {
|
||||||
if node.recharging && node.finishRecharge < firstTime {
|
if node.recharging && node.finishRecharge < firstTime {
|
||||||
firstTime = node.finishRecharge
|
firstTime = node.finishRecharge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.updateNodes(firstTime) {
|
if cm.updateNodes(firstTime) {
|
||||||
for node := range self.nodes {
|
for node := range cm.nodes {
|
||||||
if node.recharging {
|
if node.recharging {
|
||||||
node.set(node.serving, self.simReqCnt, self.sumWeight)
|
node.set(node.serving, cm.simReqCnt, cm.sumWeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.time = time
|
cm.time = time
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) canStartReq() bool {
|
func (cm *ClientManager) canStartReq() bool {
|
||||||
return self.simReqCnt < self.maxSimReq && self.rcSumValue < self.maxRcSum
|
return cm.simReqCnt < cm.maxSimReq && cm.rcSumValue < cm.maxRcSum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) queueProc() {
|
func (cm *ClientManager) queueProc() {
|
||||||
for rc := range self.resumeQueue {
|
for rc := range cm.resumeQueue {
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Millisecond * 10)
|
time.Sleep(time.Millisecond * 10)
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
self.update(mclock.Now())
|
cm.update(mclock.Now())
|
||||||
cs := self.canStartReq()
|
cs := cm.canStartReq()
|
||||||
self.lock.Unlock()
|
cm.lock.Unlock()
|
||||||
if cs {
|
if cs {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -184,41 +184,41 @@ func (self *ClientManager) queueProc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) accept(node *cmNode, time mclock.AbsTime) bool {
|
func (cm *ClientManager) accept(node *cmNode, time mclock.AbsTime) bool {
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer cm.lock.Unlock()
|
||||||
|
|
||||||
self.update(time)
|
cm.update(time)
|
||||||
if !self.canStartReq() {
|
if !cm.canStartReq() {
|
||||||
resume := make(chan bool)
|
resume := make(chan bool)
|
||||||
self.lock.Unlock()
|
cm.lock.Unlock()
|
||||||
self.resumeQueue <- resume
|
cm.resumeQueue <- resume
|
||||||
<-resume
|
<-resume
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
if _, ok := self.nodes[node]; !ok {
|
if _, ok := cm.nodes[node]; !ok {
|
||||||
return false // reject if node has been removed or manager has been stopped
|
return false // reject if node has been removed or manager has been stopped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.simReqCnt++
|
cm.simReqCnt++
|
||||||
node.set(true, self.simReqCnt, self.sumWeight)
|
node.set(true, cm.simReqCnt, cm.sumWeight)
|
||||||
node.startValue = node.rcValue
|
node.startValue = node.rcValue
|
||||||
self.update(self.time)
|
cm.update(cm.time)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) stop(node *cmNode, time mclock.AbsTime) {
|
func (cm *ClientManager) stop(node *cmNode, time mclock.AbsTime) {
|
||||||
if node.serving {
|
if node.serving {
|
||||||
self.update(time)
|
cm.update(time)
|
||||||
self.simReqCnt--
|
cm.simReqCnt--
|
||||||
node.set(false, self.simReqCnt, self.sumWeight)
|
node.set(false, cm.simReqCnt, cm.sumWeight)
|
||||||
self.update(time)
|
cm.update(time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ClientManager) processed(node *cmNode, time mclock.AbsTime) (rcValue, rcCost uint64) {
|
func (cm *ClientManager) processed(node *cmNode, time mclock.AbsTime) (rcValue, rcCost uint64) {
|
||||||
self.lock.Lock()
|
cm.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer cm.lock.Unlock()
|
||||||
|
|
||||||
self.stop(node, time)
|
cm.stop(node, time)
|
||||||
return uint64(node.rcValue), uint64(node.rcValue - node.startValue)
|
return uint64(node.rcValue), uint64(node.rcValue - node.startValue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1174,15 +1174,15 @@ type NodeInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeInfo retrieves some protocol metadata about the running host node.
|
// NodeInfo retrieves some protocol metadata about the running host node.
|
||||||
func (self *ProtocolManager) NodeInfo() *NodeInfo {
|
func (pm *ProtocolManager) NodeInfo() *NodeInfo {
|
||||||
head := self.blockchain.CurrentHeader()
|
head := pm.blockchain.CurrentHeader()
|
||||||
hash := head.Hash()
|
hash := head.Hash()
|
||||||
|
|
||||||
return &NodeInfo{
|
return &NodeInfo{
|
||||||
Network: self.networkId,
|
Network: pm.networkId,
|
||||||
Difficulty: self.blockchain.GetTd(hash, head.Number.Uint64()),
|
Difficulty: pm.blockchain.GetTd(hash, head.Number.Uint64()),
|
||||||
Genesis: self.blockchain.Genesis().Hash(),
|
Genesis: pm.blockchain.Genesis().Hash(),
|
||||||
Config: self.blockchain.Config(),
|
Config: pm.blockchain.Config(),
|
||||||
Head: hash,
|
Head: hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,47 +50,47 @@ func NewLesTxRelay(ps *peerSet, reqDist *requestDistributor) *LesTxRelay {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LesTxRelay) registerPeer(p *peer) {
|
func (relay *LesTxRelay) registerPeer(p *peer) {
|
||||||
self.lock.Lock()
|
relay.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer relay.lock.Unlock()
|
||||||
|
|
||||||
self.peerList = self.ps.AllPeers()
|
relay.peerList = relay.ps.AllPeers()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LesTxRelay) unregisterPeer(p *peer) {
|
func (relay *LesTxRelay) unregisterPeer(p *peer) {
|
||||||
self.lock.Lock()
|
relay.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer relay.lock.Unlock()
|
||||||
|
|
||||||
self.peerList = self.ps.AllPeers()
|
relay.peerList = relay.ps.AllPeers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// send sends a list of transactions to at most a given number of peers at
|
// send sends a list of transactions to at most a given number of peers at
|
||||||
// once, never resending any particular transaction to the same peer twice
|
// once, never resending any particular transaction to the same peer twice
|
||||||
func (self *LesTxRelay) send(txs types.Transactions, count int) {
|
func (relay *LesTxRelay) send(txs types.Transactions, count int) {
|
||||||
sendTo := make(map[*peer]types.Transactions)
|
sendTo := make(map[*peer]types.Transactions)
|
||||||
|
|
||||||
self.peerStartPos++ // rotate the starting position of the peer list
|
relay.peerStartPos++ // rotate the starting position of the peer list
|
||||||
if self.peerStartPos >= len(self.peerList) {
|
if relay.peerStartPos >= len(relay.peerList) {
|
||||||
self.peerStartPos = 0
|
relay.peerStartPos = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
ltr, ok := self.txSent[hash]
|
ltr, ok := relay.txSent[hash]
|
||||||
if !ok {
|
if !ok {
|
||||||
ltr = <rInfo{
|
ltr = <rInfo{
|
||||||
tx: tx,
|
tx: tx,
|
||||||
sentTo: make(map[*peer]struct{}),
|
sentTo: make(map[*peer]struct{}),
|
||||||
}
|
}
|
||||||
self.txSent[hash] = ltr
|
relay.txSent[hash] = ltr
|
||||||
self.txPending[hash] = struct{}{}
|
relay.txPending[hash] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(self.peerList) > 0 {
|
if len(relay.peerList) > 0 {
|
||||||
cnt := count
|
cnt := count
|
||||||
pos := self.peerStartPos
|
pos := relay.peerStartPos
|
||||||
for {
|
for {
|
||||||
peer := self.peerList[pos]
|
peer := relay.peerList[pos]
|
||||||
if _, ok := ltr.sentTo[peer]; !ok {
|
if _, ok := ltr.sentTo[peer]; !ok {
|
||||||
sendTo[peer] = append(sendTo[peer], tx)
|
sendTo[peer] = append(sendTo[peer], tx)
|
||||||
ltr.sentTo[peer] = struct{}{}
|
ltr.sentTo[peer] = struct{}{}
|
||||||
|
|
@ -100,10 +100,10 @@ func (self *LesTxRelay) send(txs types.Transactions, count int) {
|
||||||
break // sent it to the desired number of peers
|
break // sent it to the desired number of peers
|
||||||
}
|
}
|
||||||
pos++
|
pos++
|
||||||
if pos == len(self.peerList) {
|
if pos == len(relay.peerList) {
|
||||||
pos = 0
|
pos = 0
|
||||||
}
|
}
|
||||||
if pos == self.peerStartPos {
|
if pos == relay.peerStartPos {
|
||||||
break // tried all available peers
|
break // tried all available peers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,46 +130,46 @@ func (self *LesTxRelay) send(txs types.Transactions, count int) {
|
||||||
return func() { peer.SendTxs(reqID, cost, ll) }
|
return func() { peer.SendTxs(reqID, cost, ll) }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.reqDist.queue(rq)
|
relay.reqDist.queue(rq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LesTxRelay) Send(txs types.Transactions) {
|
func (relay *LesTxRelay) Send(txs types.Transactions) {
|
||||||
self.lock.Lock()
|
relay.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer relay.lock.Unlock()
|
||||||
|
|
||||||
self.send(txs, 3)
|
relay.send(txs, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) {
|
func (relay *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) {
|
||||||
self.lock.Lock()
|
relay.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer relay.lock.Unlock()
|
||||||
|
|
||||||
for _, hash := range mined {
|
for _, hash := range mined {
|
||||||
delete(self.txPending, hash)
|
delete(relay.txPending, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hash := range rollback {
|
for _, hash := range rollback {
|
||||||
self.txPending[hash] = struct{}{}
|
relay.txPending[hash] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(self.txPending) > 0 {
|
if len(relay.txPending) > 0 {
|
||||||
txs := make(types.Transactions, len(self.txPending))
|
txs := make(types.Transactions, len(relay.txPending))
|
||||||
i := 0
|
i := 0
|
||||||
for hash := range self.txPending {
|
for hash := range relay.txPending {
|
||||||
txs[i] = self.txSent[hash].tx
|
txs[i] = relay.txSent[hash].tx
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
self.send(txs, 1)
|
relay.send(txs, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LesTxRelay) Discard(hashes []common.Hash) {
|
func (relay *LesTxRelay) Discard(hashes []common.Hash) {
|
||||||
self.lock.Lock()
|
relay.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer relay.lock.Unlock()
|
||||||
|
|
||||||
for _, hash := range hashes {
|
for _, hash := range hashes {
|
||||||
delete(self.txSent, hash)
|
delete(relay.txSent, hash)
|
||||||
delete(self.txPending, hash)
|
delete(relay.txPending, hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,45 +116,45 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.
|
||||||
}
|
}
|
||||||
|
|
||||||
// addTrustedCheckpoint adds a trusted checkpoint to the blockchain
|
// addTrustedCheckpoint adds a trusted checkpoint to the blockchain
|
||||||
func (self *LightChain) addTrustedCheckpoint(cp trustedCheckpoint) {
|
func (bc *LightChain) addTrustedCheckpoint(cp trustedCheckpoint) {
|
||||||
if self.odr.ChtIndexer() != nil {
|
if bc.odr.ChtIndexer() != nil {
|
||||||
StoreChtRoot(self.chainDb, cp.sectionIdx, cp.sectionHead, cp.chtRoot)
|
StoreChtRoot(bc.chainDb, cp.sectionIdx, cp.sectionHead, cp.chtRoot)
|
||||||
self.odr.ChtIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead)
|
bc.odr.ChtIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead)
|
||||||
}
|
}
|
||||||
if self.odr.BloomTrieIndexer() != nil {
|
if bc.odr.BloomTrieIndexer() != nil {
|
||||||
StoreBloomTrieRoot(self.chainDb, cp.sectionIdx, cp.sectionHead, cp.bloomTrieRoot)
|
StoreBloomTrieRoot(bc.chainDb, cp.sectionIdx, cp.sectionHead, cp.bloomTrieRoot)
|
||||||
self.odr.BloomTrieIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead)
|
bc.odr.BloomTrieIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead)
|
||||||
}
|
}
|
||||||
if self.odr.BloomIndexer() != nil {
|
if bc.odr.BloomIndexer() != nil {
|
||||||
self.odr.BloomIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead)
|
bc.odr.BloomIndexer().AddKnownSectionHead(cp.sectionIdx, cp.sectionHead)
|
||||||
}
|
}
|
||||||
log.Info("Added trusted checkpoint", "chain", cp.name, "block", (cp.sectionIdx+1)*CHTFrequencyClient-1, "hash", cp.sectionHead)
|
log.Info("Added trusted checkpoint", "bc", cp.name, "block", (cp.sectionIdx+1)*CHTFrequencyClient-1, "hash", cp.sectionHead)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LightChain) getProcInterrupt() bool {
|
func (bc *LightChain) getProcInterrupt() bool {
|
||||||
return atomic.LoadInt32(&self.procInterrupt) == 1
|
return atomic.LoadInt32(&bc.procInterrupt) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Odr returns the ODR backend of the chain
|
// Odr returns the ODR backend of the chain
|
||||||
func (self *LightChain) Odr() OdrBackend {
|
func (bc *LightChain) Odr() OdrBackend {
|
||||||
return self.odr
|
return bc.odr
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadLastState loads the last known chain state from the database. This method
|
// loadLastState loads the last known chain state from the database. This method
|
||||||
// assumes that the chain manager mutex is held.
|
// assumes that the chain manager mutex is held.
|
||||||
func (self *LightChain) loadLastState() error {
|
func (bc *LightChain) loadLastState() error {
|
||||||
if head := rawdb.ReadHeadHeaderHash(self.chainDb); head == (common.Hash{}) {
|
if head := rawdb.ReadHeadHeaderHash(bc.chainDb); head == (common.Hash{}) {
|
||||||
// Corrupt or empty database, init from scratch
|
// Corrupt or empty database, init from scratch
|
||||||
self.Reset()
|
bc.Reset()
|
||||||
} else {
|
} else {
|
||||||
if header := self.GetHeaderByHash(head); header != nil {
|
if header := bc.GetHeaderByHash(head); header != nil {
|
||||||
self.hc.SetCurrentHeader(header)
|
bc.hc.SetCurrentHeader(header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue a status log and return
|
// Issue a status log and return
|
||||||
header := self.hc.CurrentHeader()
|
header := bc.hc.CurrentHeader()
|
||||||
headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
|
headerTd := bc.GetTd(header.Hash(), header.Number.Uint64())
|
||||||
log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
|
log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -171,8 +171,8 @@ func (bc *LightChain) SetHead(head uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GasLimit returns the gas limit of the current HEAD block.
|
// GasLimit returns the gas limit of the current HEAD block.
|
||||||
func (self *LightChain) GasLimit() uint64 {
|
func (bc *LightChain) GasLimit() uint64 {
|
||||||
return self.hc.CurrentHeader().GasLimit
|
return bc.hc.CurrentHeader().GasLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset purges the entire blockchain, restoring it to its genesis state.
|
// Reset purges the entire blockchain, restoring it to its genesis state.
|
||||||
|
|
@ -183,7 +183,7 @@ func (bc *LightChain) Reset() {
|
||||||
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
|
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
|
||||||
// specified genesis state.
|
// specified genesis state.
|
||||||
func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) {
|
func (bc *LightChain) ResetWithGenesisBlock(genesis *types.Block) {
|
||||||
// Dump the entire block chain and purge the caches
|
// Dump the entire block bc and purge the caches
|
||||||
bc.SetHead(0)
|
bc.SetHead(0)
|
||||||
|
|
||||||
bc.mu.Lock()
|
bc.mu.Lock()
|
||||||
|
|
@ -215,42 +215,42 @@ func (bc *LightChain) State() (*state.StateDB, error) {
|
||||||
|
|
||||||
// GetBody retrieves a block body (transactions and uncles) from the database
|
// GetBody retrieves a block body (transactions and uncles) from the database
|
||||||
// or ODR service by hash, caching it if found.
|
// or ODR service by hash, caching it if found.
|
||||||
func (self *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) {
|
func (bc *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) {
|
||||||
// Short circuit if the body's already in the cache, retrieve otherwise
|
// Short circuit if the body's already in the cache, retrieve otherwise
|
||||||
if cached, ok := self.bodyCache.Get(hash); ok {
|
if cached, ok := bc.bodyCache.Get(hash); ok {
|
||||||
body := cached.(*types.Body)
|
body := cached.(*types.Body)
|
||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
number := self.hc.GetBlockNumber(hash)
|
number := bc.hc.GetBlockNumber(hash)
|
||||||
if number == nil {
|
if number == nil {
|
||||||
return nil, errors.New("unknown block")
|
return nil, errors.New("unknown block")
|
||||||
}
|
}
|
||||||
body, err := GetBody(ctx, self.odr, hash, *number)
|
body, err := GetBody(ctx, bc.odr, hash, *number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Cache the found body for next time and return
|
// Cache the found body for next time and return
|
||||||
self.bodyCache.Add(hash, body)
|
bc.bodyCache.Add(hash, body)
|
||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBodyRLP retrieves a block body in RLP encoding from the database or
|
// GetBodyRLP retrieves a block body in RLP encoding from the database or
|
||||||
// ODR service by hash, caching it if found.
|
// ODR service by hash, caching it if found.
|
||||||
func (self *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) {
|
func (bc *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) {
|
||||||
// Short circuit if the body's already in the cache, retrieve otherwise
|
// Short circuit if the body's already in the cache, retrieve otherwise
|
||||||
if cached, ok := self.bodyRLPCache.Get(hash); ok {
|
if cached, ok := bc.bodyRLPCache.Get(hash); ok {
|
||||||
return cached.(rlp.RawValue), nil
|
return cached.(rlp.RawValue), nil
|
||||||
}
|
}
|
||||||
number := self.hc.GetBlockNumber(hash)
|
number := bc.hc.GetBlockNumber(hash)
|
||||||
if number == nil {
|
if number == nil {
|
||||||
return nil, errors.New("unknown block")
|
return nil, errors.New("unknown block")
|
||||||
}
|
}
|
||||||
body, err := GetBodyRLP(ctx, self.odr, hash, *number)
|
body, err := GetBodyRLP(ctx, bc.odr, hash, *number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Cache the found body for next time and return
|
// Cache the found body for next time and return
|
||||||
self.bodyRLPCache.Add(hash, body)
|
bc.bodyRLPCache.Add(hash, body)
|
||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,38 +263,38 @@ func (bc *LightChain) HasBlock(hash common.Hash, number uint64) bool {
|
||||||
|
|
||||||
// GetBlock retrieves a block from the database or ODR service by hash and number,
|
// GetBlock retrieves a block from the database or ODR service by hash and number,
|
||||||
// caching it if found.
|
// caching it if found.
|
||||||
func (self *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) {
|
func (bc *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) {
|
||||||
// Short circuit if the block's already in the cache, retrieve otherwise
|
// Short circuit if the block's already in the cache, retrieve otherwise
|
||||||
if block, ok := self.blockCache.Get(hash); ok {
|
if block, ok := bc.blockCache.Get(hash); ok {
|
||||||
return block.(*types.Block), nil
|
return block.(*types.Block), nil
|
||||||
}
|
}
|
||||||
block, err := GetBlock(ctx, self.odr, hash, number)
|
block, err := GetBlock(ctx, bc.odr, hash, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Cache the found block for next time and return
|
// Cache the found block for next time and return
|
||||||
self.blockCache.Add(block.Hash(), block)
|
bc.blockCache.Add(block.Hash(), block)
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByHash retrieves a block from the database or ODR service by hash,
|
// GetBlockByHash retrieves a block from the database or ODR service by hash,
|
||||||
// caching it if found.
|
// caching it if found.
|
||||||
func (self *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
func (bc *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||||
number := self.hc.GetBlockNumber(hash)
|
number := bc.hc.GetBlockNumber(hash)
|
||||||
if number == nil {
|
if number == nil {
|
||||||
return nil, errors.New("unknown block")
|
return nil, errors.New("unknown block")
|
||||||
}
|
}
|
||||||
return self.GetBlock(ctx, hash, *number)
|
return bc.GetBlock(ctx, hash, *number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByNumber retrieves a block from the database or ODR service by
|
// GetBlockByNumber retrieves a block from the database or ODR service by
|
||||||
// number, caching it (associated with its hash) if found.
|
// number, caching it (associated with its hash) if found.
|
||||||
func (self *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
|
func (bc *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
|
||||||
hash, err := GetCanonicalHash(ctx, self.odr, number)
|
hash, err := GetCanonicalHash(ctx, bc.odr, number)
|
||||||
if hash == (common.Hash{}) || err != nil {
|
if hash == (common.Hash{}) || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return self.GetBlock(ctx, hash, number)
|
return bc.GetBlock(ctx, hash, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops the blockchain service. If any imports are currently in progress
|
// Stop stops the blockchain service. If any imports are currently in progress
|
||||||
|
|
@ -312,31 +312,31 @@ func (bc *LightChain) Stop() {
|
||||||
|
|
||||||
// Rollback is designed to remove a chain of links from the database that aren't
|
// Rollback is designed to remove a chain of links from the database that aren't
|
||||||
// certain enough to be valid.
|
// certain enough to be valid.
|
||||||
func (self *LightChain) Rollback(chain []common.Hash) {
|
func (bc *LightChain) Rollback(chain []common.Hash) {
|
||||||
self.mu.Lock()
|
bc.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
for i := len(chain) - 1; i >= 0; i-- {
|
for i := len(chain) - 1; i >= 0; i-- {
|
||||||
hash := chain[i]
|
hash := chain[i]
|
||||||
|
|
||||||
if head := self.hc.CurrentHeader(); head.Hash() == hash {
|
if head := bc.hc.CurrentHeader(); head.Hash() == hash {
|
||||||
self.hc.SetCurrentHeader(self.GetHeader(head.ParentHash, head.Number.Uint64()-1))
|
bc.hc.SetCurrentHeader(bc.GetHeader(head.ParentHash, head.Number.Uint64()-1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// postChainEvents iterates over the events generated by a chain insertion and
|
// postChainEvents iterates over the events generated by a chain insertion and
|
||||||
// posts them into the event feed.
|
// posts them into the event feed.
|
||||||
func (self *LightChain) postChainEvents(events []interface{}) {
|
func (chain *LightChain) postChainEvents(events []interface{}) {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
switch ev := event.(type) {
|
switch ev := event.(type) {
|
||||||
case core.ChainEvent:
|
case core.ChainEvent:
|
||||||
if self.CurrentHeader().Hash() == ev.Hash {
|
if chain.CurrentHeader().Hash() == ev.Hash {
|
||||||
self.chainHeadFeed.Send(core.ChainHeadEvent{Block: ev.Block})
|
chain.chainHeadFeed.Send(core.ChainHeadEvent{Block: ev.Block})
|
||||||
}
|
}
|
||||||
self.chainFeed.Send(ev)
|
chain.chainFeed.Send(ev)
|
||||||
case core.ChainSideEvent:
|
case core.ChainSideEvent:
|
||||||
self.chainSideFeed.Send(ev)
|
chain.chainSideFeed.Send(ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,28 +352,28 @@ func (self *LightChain) postChainEvents(events []interface{}) {
|
||||||
//
|
//
|
||||||
// In the case of a light chain, InsertHeaderChain also creates and posts light
|
// In the case of a light chain, InsertHeaderChain also creates and posts light
|
||||||
// chain events when necessary.
|
// chain events when necessary.
|
||||||
func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
|
func (bc *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if i, err := self.hc.ValidateHeaderChain(chain, checkFreq); err != nil {
|
if i, err := bc.hc.ValidateHeaderChain(chain, checkFreq); err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure only one thread manipulates the chain at once
|
// Make sure only one thread manipulates the chain at once
|
||||||
self.chainmu.Lock()
|
bc.chainmu.Lock()
|
||||||
defer func() {
|
defer func() {
|
||||||
self.chainmu.Unlock()
|
bc.chainmu.Unlock()
|
||||||
time.Sleep(time.Millisecond * 10) // ugly hack; do not hog chain lock in case syncing is CPU-limited by validation
|
time.Sleep(time.Millisecond * 10) // ugly hack; do not hog chain lock in case syncing is CPU-limited by validation
|
||||||
}()
|
}()
|
||||||
|
|
||||||
self.wg.Add(1)
|
bc.wg.Add(1)
|
||||||
defer self.wg.Done()
|
defer bc.wg.Done()
|
||||||
|
|
||||||
var events []interface{}
|
var events []interface{}
|
||||||
whFunc := func(header *types.Header) error {
|
whFunc := func(header *types.Header) error {
|
||||||
self.mu.Lock()
|
bc.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer bc.mu.Unlock()
|
||||||
|
|
||||||
status, err := self.hc.WriteHeader(header)
|
status, err := bc.hc.WriteHeader(header)
|
||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case core.CanonStatTy:
|
case core.CanonStatTy:
|
||||||
|
|
@ -386,39 +386,39 @@ func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i, err := self.hc.InsertHeaderChain(chain, whFunc, start)
|
i, err := bc.hc.InsertHeaderChain(chain, whFunc, start)
|
||||||
self.postChainEvents(events)
|
bc.postChainEvents(events)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentHeader retrieves the current head header of the canonical chain. The
|
// CurrentHeader retrieves the current head header of the canonical chain. The
|
||||||
// header is retrieved from the HeaderChain's internal cache.
|
// header is retrieved from the HeaderChain's internal cache.
|
||||||
func (self *LightChain) CurrentHeader() *types.Header {
|
func (bc *LightChain) CurrentHeader() *types.Header {
|
||||||
return self.hc.CurrentHeader()
|
return bc.hc.CurrentHeader()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||||
// database by hash and number, caching it if found.
|
// database by hash and number, caching it if found.
|
||||||
func (self *LightChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
func (bc *LightChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||||
return self.hc.GetTd(hash, number)
|
return bc.hc.GetTd(hash, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTdByHash retrieves a block's total difficulty in the canonical chain from the
|
// GetTdByHash retrieves a block's total difficulty in the canonical chain from the
|
||||||
// database by hash, caching it if found.
|
// database by hash, caching it if found.
|
||||||
func (self *LightChain) GetTdByHash(hash common.Hash) *big.Int {
|
func (bc *LightChain) GetTdByHash(hash common.Hash) *big.Int {
|
||||||
return self.hc.GetTdByHash(hash)
|
return bc.hc.GetTdByHash(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeader retrieves a block header from the database by hash and number,
|
// GetHeader retrieves a block header from the database by hash and number,
|
||||||
// caching it if found.
|
// caching it if found.
|
||||||
func (self *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header {
|
func (bc *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||||
return self.hc.GetHeader(hash, number)
|
return bc.hc.GetHeader(hash, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeaderByHash retrieves a block header from the database by hash, caching it if
|
// GetHeaderByHash retrieves a block header from the database by hash, caching it if
|
||||||
// found.
|
// found.
|
||||||
func (self *LightChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
func (bc *LightChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
||||||
return self.hc.GetHeaderByHash(hash)
|
return bc.hc.GetHeaderByHash(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasHeader checks if a block header is present in the database or not, caching
|
// HasHeader checks if a block header is present in the database or not, caching
|
||||||
|
|
@ -429,43 +429,43 @@ func (bc *LightChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||||
|
|
||||||
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
||||||
// hash, fetching towards the genesis block.
|
// hash, fetching towards the genesis block.
|
||||||
func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash {
|
func (bc *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash {
|
||||||
return self.hc.GetBlockHashesFromHash(hash, max)
|
return bc.hc.GetBlockHashesFromHash(hash, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||||
// caching it (associated with its hash) if found.
|
// caching it (associated with its hash) if found.
|
||||||
func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header {
|
func (bc *LightChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||||
return self.hc.GetHeaderByNumber(number)
|
return bc.hc.GetHeaderByNumber(number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeaderByNumberOdr retrieves a block header from the database or network
|
// GetHeaderByNumberOdr retrieves a block header from the database or network
|
||||||
// by number, caching it (associated with its hash) if found.
|
// by number, caching it (associated with its hash) if found.
|
||||||
func (self *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) {
|
func (bc *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) {
|
||||||
if header := self.hc.GetHeaderByNumber(number); header != nil {
|
if header := bc.hc.GetHeaderByNumber(number); header != nil {
|
||||||
return header, nil
|
return header, nil
|
||||||
}
|
}
|
||||||
return GetHeaderByNumber(ctx, self.odr, number)
|
return GetHeaderByNumber(ctx, bc.odr, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config retrieves the header chain's chain configuration.
|
// Config retrieves the header chain's chain configuration.
|
||||||
func (self *LightChain) Config() *params.ChainConfig { return self.hc.Config() }
|
func (bc *LightChain) Config() *params.ChainConfig { return bc.hc.Config() }
|
||||||
|
|
||||||
func (self *LightChain) SyncCht(ctx context.Context) bool {
|
func (bc *LightChain) SyncCht(ctx context.Context) bool {
|
||||||
if self.odr.ChtIndexer() == nil {
|
if bc.odr.ChtIndexer() == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
headNum := self.CurrentHeader().Number.Uint64()
|
headNum := bc.CurrentHeader().Number.Uint64()
|
||||||
chtCount, _, _ := self.odr.ChtIndexer().Sections()
|
chtCount, _, _ := bc.odr.ChtIndexer().Sections()
|
||||||
if headNum+1 < chtCount*CHTFrequencyClient {
|
if headNum+1 < chtCount*CHTFrequencyClient {
|
||||||
num := chtCount*CHTFrequencyClient - 1
|
num := chtCount*CHTFrequencyClient - 1
|
||||||
header, err := GetHeaderByNumber(ctx, self.odr, num)
|
header, err := GetHeaderByNumber(ctx, bc.odr, num)
|
||||||
if header != nil && err == nil {
|
if header != nil && err == nil {
|
||||||
self.mu.Lock()
|
bc.mu.Lock()
|
||||||
if self.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() {
|
if bc.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() {
|
||||||
self.hc.SetCurrentHeader(header)
|
bc.hc.SetCurrentHeader(header)
|
||||||
}
|
}
|
||||||
self.mu.Unlock()
|
bc.mu.Unlock()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -474,38 +474,38 @@ func (self *LightChain) SyncCht(ctx context.Context) bool {
|
||||||
|
|
||||||
// LockChain locks the chain mutex for reading so that multiple canonical hashes can be
|
// LockChain locks the chain mutex for reading so that multiple canonical hashes can be
|
||||||
// retrieved while it is guaranteed that they belong to the same version of the chain
|
// retrieved while it is guaranteed that they belong to the same version of the chain
|
||||||
func (self *LightChain) LockChain() {
|
func (bc *LightChain) LockChain() {
|
||||||
self.chainmu.RLock()
|
bc.chainmu.RLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnlockChain unlocks the chain mutex
|
// UnlockChain unlocks the chain mutex
|
||||||
func (self *LightChain) UnlockChain() {
|
func (bc *LightChain) UnlockChain() {
|
||||||
self.chainmu.RUnlock()
|
bc.chainmu.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeChainEvent registers a subscription of ChainEvent.
|
// SubscribeChainEvent registers a subscription of ChainEvent.
|
||||||
func (self *LightChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
|
func (bc *LightChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
|
||||||
return self.scope.Track(self.chainFeed.Subscribe(ch))
|
return bc.scope.Track(bc.chainFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeChainHeadEvent registers a subscription of ChainHeadEvent.
|
// SubscribeChainHeadEvent registers a subscription of ChainHeadEvent.
|
||||||
func (self *LightChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
func (bc *LightChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||||
return self.scope.Track(self.chainHeadFeed.Subscribe(ch))
|
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeChainSideEvent registers a subscription of ChainSideEvent.
|
// SubscribeChainSideEvent registers a subscription of ChainSideEvent.
|
||||||
func (self *LightChain) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
|
func (bc *LightChain) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
|
||||||
return self.scope.Track(self.chainSideFeed.Subscribe(ch))
|
return bc.scope.Track(bc.chainSideFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeLogsEvent implements the interface of filters.Backend
|
// SubscribeLogsEvent implements the interface of filters.Backend
|
||||||
// LightChain does not send logs events, so return an empty subscription.
|
// LightChain does not send logs events, so return an empty subscription.
|
||||||
func (self *LightChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
func (bc *LightChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
||||||
return self.scope.Track(new(event.Feed).Subscribe(ch))
|
return bc.scope.Track(new(event.Feed).Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeRemovedLogsEvent implements the interface of filters.Backend
|
// SubscribeRemovedLogsEvent implements the interface of filters.Backend
|
||||||
// LightChain does not send core.RemovedLogsEvent, so return an empty subscription.
|
// LightChain does not send core.RemovedLogsEvent, so return an empty subscription.
|
||||||
func (self *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
|
func (bc *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
|
||||||
return self.scope.Track(new(event.Feed).Subscribe(ch))
|
return bc.scope.Track(new(event.Feed).Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -388,73 +388,73 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
|
||||||
|
|
||||||
// add validates a new transaction and sets its state pending if processable.
|
// add validates a new transaction and sets its state pending if processable.
|
||||||
// It also updates the locally stored nonce if necessary.
|
// It also updates the locally stored nonce if necessary.
|
||||||
func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
|
func (pool *TxPool) add(ctx context.Context, tx *types.Transaction) error {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
|
|
||||||
if self.pending[hash] != nil {
|
if pool.pending[hash] != nil {
|
||||||
return fmt.Errorf("Known transaction (%x)", hash[:4])
|
return fmt.Errorf("Known transaction (%x)", hash[:4])
|
||||||
}
|
}
|
||||||
err := self.validateTx(ctx, tx)
|
err := pool.validateTx(ctx, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := self.pending[hash]; !ok {
|
if _, ok := pool.pending[hash]; !ok {
|
||||||
self.pending[hash] = tx
|
pool.pending[hash] = tx
|
||||||
|
|
||||||
nonce := tx.Nonce() + 1
|
nonce := tx.Nonce() + 1
|
||||||
|
|
||||||
addr, _ := types.Sender(self.signer, tx)
|
addr, _ := types.Sender(pool.signer, tx)
|
||||||
if nonce > self.nonce[addr] {
|
if nonce > pool.nonce[addr] {
|
||||||
self.nonce[addr] = nonce
|
pool.nonce[addr] = nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the subscribers. This event is posted in a goroutine
|
// Notify the subscribers. This event is posted in a goroutine
|
||||||
// because it's possible that somewhere during the post "Remove transaction"
|
// because it's possible that somewhere during the post "Remove transaction"
|
||||||
// gets called which will then wait for the global tx pool lock and deadlock.
|
// gets called which will then wait for the global tx pool lock and deadlock.
|
||||||
go self.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}})
|
go pool.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print a log message if low enough level is set
|
// Print a log message if low enough level is set
|
||||||
log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(self.signer, tx); return from }}, "to", tx.To())
|
log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(pool.signer, tx); return from }}, "to", tx.To())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds a transaction to the pool if valid and passes it to the tx relay
|
// Add adds a transaction to the pool if valid and passes it to the tx relay
|
||||||
// backend
|
// backend
|
||||||
func (self *TxPool) Add(ctx context.Context, tx *types.Transaction) error {
|
func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error {
|
||||||
self.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer pool.mu.Unlock()
|
||||||
|
|
||||||
data, err := rlp.EncodeToBytes(tx)
|
data, err := rlp.EncodeToBytes(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.add(ctx, tx); err != nil {
|
if err := pool.add(ctx, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//fmt.Println("Send", tx.Hash())
|
//fmt.Println("Send", tx.Hash())
|
||||||
self.relay.Send(types.Transactions{tx})
|
pool.relay.Send(types.Transactions{tx})
|
||||||
|
|
||||||
self.chainDb.Put(tx.Hash().Bytes(), data)
|
pool.chainDb.Put(tx.Hash().Bytes(), data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTransactions adds all valid transactions to the pool and passes them to
|
// AddTransactions adds all valid transactions to the pool and passes them to
|
||||||
// the tx relay backend
|
// the tx relay backend
|
||||||
func (self *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) {
|
func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) {
|
||||||
self.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer pool.mu.Unlock()
|
||||||
var sendTx types.Transactions
|
var sendTx types.Transactions
|
||||||
|
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
if err := self.add(ctx, tx); err == nil {
|
if err := pool.add(ctx, tx); err == nil {
|
||||||
sendTx = append(sendTx, tx)
|
sendTx = append(sendTx, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(sendTx) > 0 {
|
if len(sendTx) > 0 {
|
||||||
self.relay.Send(sendTx)
|
pool.relay.Send(sendTx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,13 +470,13 @@ func (tp *TxPool) GetTransaction(hash common.Hash) *types.Transaction {
|
||||||
|
|
||||||
// GetTransactions returns all currently processable transactions.
|
// GetTransactions returns all currently processable transactions.
|
||||||
// The returned slice may be modified by the caller.
|
// The returned slice may be modified by the caller.
|
||||||
func (self *TxPool) GetTransactions() (txs types.Transactions, err error) {
|
func (pool *TxPool) GetTransactions() (txs types.Transactions, err error) {
|
||||||
self.mu.RLock()
|
pool.mu.RLock()
|
||||||
defer self.mu.RUnlock()
|
defer pool.mu.RUnlock()
|
||||||
|
|
||||||
txs = make(types.Transactions, len(self.pending))
|
txs = make(types.Transactions, len(pool.pending))
|
||||||
i := 0
|
i := 0
|
||||||
for _, tx := range self.pending {
|
for _, tx := range pool.pending {
|
||||||
txs[i] = tx
|
txs[i] = tx
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
@ -485,14 +485,14 @@ func (self *TxPool) GetTransactions() (txs types.Transactions, err error) {
|
||||||
|
|
||||||
// Content retrieves the data content of the transaction pool, returning all the
|
// Content retrieves the data content of the transaction pool, returning all the
|
||||||
// pending as well as queued transactions, grouped by account and nonce.
|
// pending as well as queued transactions, grouped by account and nonce.
|
||||||
func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
|
func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
|
||||||
self.mu.RLock()
|
pool.mu.RLock()
|
||||||
defer self.mu.RUnlock()
|
defer pool.mu.RUnlock()
|
||||||
|
|
||||||
// Retrieve all the pending transactions and sort by account and by nonce
|
// Retrieve all the pending transactions and sort by account and by nonce
|
||||||
pending := make(map[common.Address]types.Transactions)
|
pending := make(map[common.Address]types.Transactions)
|
||||||
for _, tx := range self.pending {
|
for _, tx := range pool.pending {
|
||||||
account, _ := types.Sender(self.signer, tx)
|
account, _ := types.Sender(pool.signer, tx)
|
||||||
pending[account] = append(pending[account], tx)
|
pending[account] = append(pending[account], tx)
|
||||||
}
|
}
|
||||||
// There are no queued transactions in a light pool, just return an empty map
|
// There are no queued transactions in a light pool, just return an empty map
|
||||||
|
|
@ -501,18 +501,18 @@ func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTransactions removes all given transactions from the pool.
|
// RemoveTransactions removes all given transactions from the pool.
|
||||||
func (self *TxPool) RemoveTransactions(txs types.Transactions) {
|
func (pool *TxPool) RemoveTransactions(txs types.Transactions) {
|
||||||
self.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer pool.mu.Unlock()
|
||||||
var hashes []common.Hash
|
var hashes []common.Hash
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
//self.RemoveTx(tx.Hash())
|
//pool.RemoveTx(tx.Hash())
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
delete(self.pending, hash)
|
delete(pool.pending, hash)
|
||||||
self.chainDb.Delete(hash[:])
|
pool.chainDb.Delete(hash[:])
|
||||||
hashes = append(hashes, hash)
|
hashes = append(hashes, hash)
|
||||||
}
|
}
|
||||||
self.relay.Discard(hashes)
|
pool.relay.Discard(hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTx removes the transaction with the given hash from the pool.
|
// RemoveTx removes the transaction with the given hash from the pool.
|
||||||
|
|
|
||||||
|
|
@ -36,19 +36,19 @@ type testTxRelay struct {
|
||||||
send, discard, mined chan int
|
send, discard, mined chan int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testTxRelay) Send(txs types.Transactions) {
|
func (relay *testTxRelay) Send(txs types.Transactions) {
|
||||||
self.send <- len(txs)
|
relay.send <- len(txs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) {
|
func (relay *testTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) {
|
||||||
m := len(mined)
|
m := len(mined)
|
||||||
if m != 0 {
|
if m != 0 {
|
||||||
self.mined <- m
|
relay.mined <- m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testTxRelay) Discard(hashes []common.Hash) {
|
func (relay *testTxRelay) Discard(hashes []common.Hash) {
|
||||||
self.discard <- len(hashes)
|
relay.discard <- len(hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
const poolTestTxs = 1000
|
const poolTestTxs = 1000
|
||||||
|
|
|
||||||
|
|
@ -49,70 +49,70 @@ func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent
|
||||||
return miner
|
return miner
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) Work() chan<- *Work { return self.workCh }
|
func (agent *CpuAgent) Work() chan<- *Work { return agent.workCh }
|
||||||
func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch }
|
func (agent *CpuAgent) SetReturnCh(ch chan<- *Result) { agent.returnCh = ch }
|
||||||
|
|
||||||
func (self *CpuAgent) Stop() {
|
func (agent *CpuAgent) Stop() {
|
||||||
if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) {
|
if !atomic.CompareAndSwapInt32(&agent.isMining, 1, 0) {
|
||||||
return // agent already stopped
|
return // agent already stopped
|
||||||
}
|
}
|
||||||
self.stop <- struct{}{}
|
agent.stop <- struct{}{}
|
||||||
done:
|
done:
|
||||||
// Empty work channel
|
// Empty work channel
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-self.workCh:
|
case <-agent.workCh:
|
||||||
default:
|
default:
|
||||||
break done
|
break done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) Start() {
|
func (agent *CpuAgent) Start() {
|
||||||
if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
|
if !atomic.CompareAndSwapInt32(&agent.isMining, 0, 1) {
|
||||||
return // agent already started
|
return // agent already started
|
||||||
}
|
}
|
||||||
go self.update()
|
go agent.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) update() {
|
func (agent *CpuAgent) update() {
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case work := <-self.workCh:
|
case work := <-agent.workCh:
|
||||||
self.mu.Lock()
|
agent.mu.Lock()
|
||||||
if self.quitCurrentOp != nil {
|
if agent.quitCurrentOp != nil {
|
||||||
close(self.quitCurrentOp)
|
close(agent.quitCurrentOp)
|
||||||
}
|
}
|
||||||
self.quitCurrentOp = make(chan struct{})
|
agent.quitCurrentOp = make(chan struct{})
|
||||||
go self.mine(work, self.quitCurrentOp)
|
go agent.mine(work, agent.quitCurrentOp)
|
||||||
self.mu.Unlock()
|
agent.mu.Unlock()
|
||||||
case <-self.stop:
|
case <-agent.stop:
|
||||||
self.mu.Lock()
|
agent.mu.Lock()
|
||||||
if self.quitCurrentOp != nil {
|
if agent.quitCurrentOp != nil {
|
||||||
close(self.quitCurrentOp)
|
close(agent.quitCurrentOp)
|
||||||
self.quitCurrentOp = nil
|
agent.quitCurrentOp = nil
|
||||||
}
|
}
|
||||||
self.mu.Unlock()
|
agent.mu.Unlock()
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
|
func (agent *CpuAgent) mine(work *Work, stop <-chan struct{}) {
|
||||||
if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil {
|
if result, err := agent.engine.Seal(agent.chain, work.Block, stop); result != nil {
|
||||||
log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
|
log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
|
||||||
self.returnCh <- &Result{work, result}
|
agent.returnCh <- &Result{work, result}
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Block sealing failed", "err", err)
|
log.Warn("Block sealing failed", "err", err)
|
||||||
}
|
}
|
||||||
self.returnCh <- nil
|
agent.returnCh <- nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuAgent) GetHashRate() int64 {
|
func (agent *CpuAgent) GetHashRate() int64 {
|
||||||
if pow, ok := self.engine.(consensus.PoW); ok {
|
if pow, ok := agent.engine.(consensus.PoW); ok {
|
||||||
return int64(pow.Hashrate())
|
return int64(pow.Hashrate())
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -75,25 +75,25 @@ func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine con
|
||||||
// It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and
|
// It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and
|
||||||
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
|
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
|
||||||
// and halt your mining operation for as long as the DOS continues.
|
// and halt your mining operation for as long as the DOS continues.
|
||||||
func (self *Miner) update() {
|
func (miner *Miner) update() {
|
||||||
events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
||||||
out:
|
out:
|
||||||
for ev := range events.Chan() {
|
for ev := range events.Chan() {
|
||||||
switch ev.Data.(type) {
|
switch ev.Data.(type) {
|
||||||
case downloader.StartEvent:
|
case downloader.StartEvent:
|
||||||
atomic.StoreInt32(&self.canStart, 0)
|
atomic.StoreInt32(&miner.canStart, 0)
|
||||||
if self.Mining() {
|
if miner.Mining() {
|
||||||
self.Stop()
|
miner.Stop()
|
||||||
atomic.StoreInt32(&self.shouldStart, 1)
|
atomic.StoreInt32(&miner.shouldStart, 1)
|
||||||
log.Info("Mining aborted due to sync")
|
log.Info("Mining aborted due to sync")
|
||||||
}
|
}
|
||||||
case downloader.DoneEvent, downloader.FailedEvent:
|
case downloader.DoneEvent, downloader.FailedEvent:
|
||||||
shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
|
shouldStart := atomic.LoadInt32(&miner.shouldStart) == 1
|
||||||
|
|
||||||
atomic.StoreInt32(&self.canStart, 1)
|
atomic.StoreInt32(&miner.canStart, 1)
|
||||||
atomic.StoreInt32(&self.shouldStart, 0)
|
atomic.StoreInt32(&miner.shouldStart, 0)
|
||||||
if shouldStart {
|
if shouldStart {
|
||||||
self.Start(self.coinbase)
|
miner.Start(miner.coinbase)
|
||||||
}
|
}
|
||||||
// unsubscribe. we're only interested in this event once
|
// unsubscribe. we're only interested in this event once
|
||||||
events.Unsubscribe()
|
events.Unsubscribe()
|
||||||
|
|
@ -103,50 +103,50 @@ out:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) Start(coinbase common.Address) {
|
func (miner *Miner) Start(coinbase common.Address) {
|
||||||
atomic.StoreInt32(&self.shouldStart, 1)
|
atomic.StoreInt32(&miner.shouldStart, 1)
|
||||||
self.SetEtherbase(coinbase)
|
miner.SetEtherbase(coinbase)
|
||||||
|
|
||||||
if atomic.LoadInt32(&self.canStart) == 0 {
|
if atomic.LoadInt32(&miner.canStart) == 0 {
|
||||||
log.Info("Network syncing, will start miner afterwards")
|
log.Info("Network syncing, will start miner afterwards")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&self.mining, 1)
|
atomic.StoreInt32(&miner.mining, 1)
|
||||||
|
|
||||||
log.Info("Starting mining operation")
|
log.Info("Starting mining operation")
|
||||||
self.worker.start()
|
miner.worker.start()
|
||||||
self.worker.commitNewWork()
|
miner.worker.commitNewWork()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) Stop() {
|
func (miner *Miner) Stop() {
|
||||||
self.worker.stop()
|
miner.worker.stop()
|
||||||
atomic.StoreInt32(&self.mining, 0)
|
atomic.StoreInt32(&miner.mining, 0)
|
||||||
atomic.StoreInt32(&self.shouldStart, 0)
|
atomic.StoreInt32(&miner.shouldStart, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) Register(agent Agent) {
|
func (miner *Miner) Register(agent Agent) {
|
||||||
if self.Mining() {
|
if miner.Mining() {
|
||||||
agent.Start()
|
agent.Start()
|
||||||
}
|
}
|
||||||
self.worker.register(agent)
|
miner.worker.register(agent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) Unregister(agent Agent) {
|
func (miner *Miner) Unregister(agent Agent) {
|
||||||
self.worker.unregister(agent)
|
miner.worker.unregister(agent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) Mining() bool {
|
func (miner *Miner) Mining() bool {
|
||||||
return atomic.LoadInt32(&self.mining) > 0
|
return atomic.LoadInt32(&miner.mining) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) HashRate() (tot int64) {
|
func (miner *Miner) HashRate() (tot int64) {
|
||||||
if pow, ok := self.engine.(consensus.PoW); ok {
|
if pow, ok := miner.engine.(consensus.PoW); ok {
|
||||||
tot += int64(pow.Hashrate())
|
tot += int64(pow.Hashrate())
|
||||||
}
|
}
|
||||||
// do we care this might race? is it worth we're rewriting some
|
// do we care this might race? is it worth we're rewriting some
|
||||||
// aspects of the worker/locking up agents so we can get an accurate
|
// aspects of the worker/locking up agents so we can get an accurate
|
||||||
// hashrate?
|
// hashrate?
|
||||||
for agent := range self.worker.agents {
|
for agent := range miner.worker.agents {
|
||||||
if _, ok := agent.(*CpuAgent); !ok {
|
if _, ok := agent.(*CpuAgent); !ok {
|
||||||
tot += agent.GetHashRate()
|
tot += agent.GetHashRate()
|
||||||
}
|
}
|
||||||
|
|
@ -154,17 +154,17 @@ func (self *Miner) HashRate() (tot int64) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) SetExtra(extra []byte) error {
|
func (miner *Miner) SetExtra(extra []byte) error {
|
||||||
if uint64(len(extra)) > params.MaximumExtraDataSize {
|
if uint64(len(extra)) > params.MaximumExtraDataSize {
|
||||||
return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
|
return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
|
||||||
}
|
}
|
||||||
self.worker.setExtra(extra)
|
miner.worker.setExtra(extra)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pending returns the currently pending block and associated state.
|
// Pending returns the currently pending block and associated state.
|
||||||
func (self *Miner) Pending() (*types.Block, *state.StateDB) {
|
func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
|
||||||
return self.worker.pending()
|
return miner.worker.pending()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PendingBlock returns the currently pending block.
|
// PendingBlock returns the currently pending block.
|
||||||
|
|
@ -172,11 +172,11 @@ func (self *Miner) Pending() (*types.Block, *state.StateDB) {
|
||||||
// Note, to access both the pending block and the pending state
|
// Note, to access both the pending block and the pending state
|
||||||
// simultaneously, please use Pending(), as the pending state can
|
// simultaneously, please use Pending(), as the pending state can
|
||||||
// change between multiple method calls
|
// change between multiple method calls
|
||||||
func (self *Miner) PendingBlock() *types.Block {
|
func (miner *Miner) PendingBlock() *types.Block {
|
||||||
return self.worker.pendingBlock()
|
return miner.worker.pendingBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Miner) SetEtherbase(addr common.Address) {
|
func (miner *Miner) SetEtherbase(addr common.Address) {
|
||||||
self.coinbase = addr
|
miner.coinbase = addr
|
||||||
self.worker.setEtherbase(addr)
|
miner.worker.setEtherbase(addr)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
250
miner/worker.go
250
miner/worker.go
|
|
@ -51,7 +51,7 @@ const (
|
||||||
chainSideChanSize = 10
|
chainSideChanSize = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
// Agent can register themself with the worker
|
// Agent can register themw with the worker
|
||||||
type Agent interface {
|
type Agent interface {
|
||||||
Work() chan<- *Work
|
Work() chan<- *Work
|
||||||
SetReturnCh(chan<- *Result)
|
SetReturnCh(chan<- *Result)
|
||||||
|
|
@ -163,143 +163,143 @@ func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase com
|
||||||
return worker
|
return worker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) setEtherbase(addr common.Address) {
|
func (w *worker) setEtherbase(addr common.Address) {
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
self.coinbase = addr
|
w.coinbase = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) setExtra(extra []byte) {
|
func (w *worker) setExtra(extra []byte) {
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
self.extra = extra
|
w.extra = extra
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) pending() (*types.Block, *state.StateDB) {
|
func (w *worker) pending() (*types.Block, *state.StateDB) {
|
||||||
if atomic.LoadInt32(&self.mining) == 0 {
|
if atomic.LoadInt32(&w.mining) == 0 {
|
||||||
// return a snapshot to avoid contention on currentMu mutex
|
// return a snapshot to avoid contention on currentMu mutex
|
||||||
self.snapshotMu.RLock()
|
w.snapshotMu.RLock()
|
||||||
defer self.snapshotMu.RUnlock()
|
defer w.snapshotMu.RUnlock()
|
||||||
return self.snapshotBlock, self.snapshotState.Copy()
|
return w.snapshotBlock, w.snapshotState.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentMu.Lock()
|
w.currentMu.Lock()
|
||||||
defer self.currentMu.Unlock()
|
defer w.currentMu.Unlock()
|
||||||
return self.current.Block, self.current.state.Copy()
|
return w.current.Block, w.current.state.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) pendingBlock() *types.Block {
|
func (w *worker) pendingBlock() *types.Block {
|
||||||
if atomic.LoadInt32(&self.mining) == 0 {
|
if atomic.LoadInt32(&w.mining) == 0 {
|
||||||
// return a snapshot to avoid contention on currentMu mutex
|
// return a snapshot to avoid contention on currentMu mutex
|
||||||
self.snapshotMu.RLock()
|
w.snapshotMu.RLock()
|
||||||
defer self.snapshotMu.RUnlock()
|
defer w.snapshotMu.RUnlock()
|
||||||
return self.snapshotBlock
|
return w.snapshotBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentMu.Lock()
|
w.currentMu.Lock()
|
||||||
defer self.currentMu.Unlock()
|
defer w.currentMu.Unlock()
|
||||||
return self.current.Block
|
return w.current.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) start() {
|
func (w *worker) start() {
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
atomic.StoreInt32(&self.mining, 1)
|
atomic.StoreInt32(&w.mining, 1)
|
||||||
|
|
||||||
// spin up agents
|
// spin up agents
|
||||||
for agent := range self.agents {
|
for agent := range w.agents {
|
||||||
agent.Start()
|
agent.Start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) stop() {
|
func (w *worker) stop() {
|
||||||
self.wg.Wait()
|
w.wg.Wait()
|
||||||
|
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&w.mining) == 1 {
|
||||||
for agent := range self.agents {
|
for agent := range w.agents {
|
||||||
agent.Stop()
|
agent.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&self.mining, 0)
|
atomic.StoreInt32(&w.mining, 0)
|
||||||
atomic.StoreInt32(&self.atWork, 0)
|
atomic.StoreInt32(&w.atWork, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) register(agent Agent) {
|
func (w *worker) register(agent Agent) {
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
self.agents[agent] = struct{}{}
|
w.agents[agent] = struct{}{}
|
||||||
agent.SetReturnCh(self.recv)
|
agent.SetReturnCh(w.recv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) unregister(agent Agent) {
|
func (w *worker) unregister(agent Agent) {
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
delete(self.agents, agent)
|
delete(w.agents, agent)
|
||||||
agent.Stop()
|
agent.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) update() {
|
func (w *worker) update() {
|
||||||
defer self.txsSub.Unsubscribe()
|
defer w.txsSub.Unsubscribe()
|
||||||
defer self.chainHeadSub.Unsubscribe()
|
defer w.chainHeadSub.Unsubscribe()
|
||||||
defer self.chainSideSub.Unsubscribe()
|
defer w.chainSideSub.Unsubscribe()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// A real event arrived, process interesting content
|
// A real event arrived, process interesting content
|
||||||
select {
|
select {
|
||||||
// Handle ChainHeadEvent
|
// Handle ChainHeadEvent
|
||||||
case <-self.chainHeadCh:
|
case <-w.chainHeadCh:
|
||||||
self.commitNewWork()
|
w.commitNewWork()
|
||||||
|
|
||||||
// Handle ChainSideEvent
|
// Handle ChainSideEvent
|
||||||
case ev := <-self.chainSideCh:
|
case ev := <-w.chainSideCh:
|
||||||
self.uncleMu.Lock()
|
w.uncleMu.Lock()
|
||||||
self.possibleUncles[ev.Block.Hash()] = ev.Block
|
w.possibleUncles[ev.Block.Hash()] = ev.Block
|
||||||
self.uncleMu.Unlock()
|
w.uncleMu.Unlock()
|
||||||
|
|
||||||
// Handle NewTxsEvent
|
// Handle NewTxsEvent
|
||||||
case ev := <-self.txsCh:
|
case ev := <-w.txsCh:
|
||||||
// Apply transactions to the pending state if we're not mining.
|
// Apply transactions to the pending state if we're not mining.
|
||||||
//
|
//
|
||||||
// Note all transactions received may not be continuous with transactions
|
// Note all transactions received may not be continuous with transactions
|
||||||
// already included in the current mining block. These transactions will
|
// already included in the current mining block. These transactions will
|
||||||
// be automatically eliminated.
|
// be automatically eliminated.
|
||||||
if atomic.LoadInt32(&self.mining) == 0 {
|
if atomic.LoadInt32(&w.mining) == 0 {
|
||||||
self.currentMu.Lock()
|
w.currentMu.Lock()
|
||||||
txs := make(map[common.Address]types.Transactions)
|
txs := make(map[common.Address]types.Transactions)
|
||||||
for _, tx := range ev.Txs {
|
for _, tx := range ev.Txs {
|
||||||
acc, _ := types.Sender(self.current.signer, tx)
|
acc, _ := types.Sender(w.current.signer, tx)
|
||||||
txs[acc] = append(txs[acc], tx)
|
txs[acc] = append(txs[acc], tx)
|
||||||
}
|
}
|
||||||
txset := types.NewTransactionsByPriceAndNonce(self.current.signer, txs)
|
txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs)
|
||||||
self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase)
|
w.current.commitTransactions(w.mux, txset, w.chain, w.coinbase)
|
||||||
self.updateSnapshot()
|
w.updateSnapshot()
|
||||||
self.currentMu.Unlock()
|
w.currentMu.Unlock()
|
||||||
} else {
|
} else {
|
||||||
// If we're mining, but nothing is being processed, wake on new transactions
|
// If we're mining, but nothing is being processed, wake on new transactions
|
||||||
if self.config.Clique != nil && self.config.Clique.Period == 0 {
|
if w.config.Clique != nil && w.config.Clique.Period == 0 {
|
||||||
self.commitNewWork()
|
w.commitNewWork()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// System stopped
|
// System stopped
|
||||||
case <-self.txsSub.Err():
|
case <-w.txsSub.Err():
|
||||||
return
|
return
|
||||||
case <-self.chainHeadSub.Err():
|
case <-w.chainHeadSub.Err():
|
||||||
return
|
return
|
||||||
case <-self.chainSideSub.Err():
|
case <-w.chainSideSub.Err():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) wait() {
|
func (w *worker) wait() {
|
||||||
for {
|
for {
|
||||||
mustCommitNewWork := true
|
mustCommitNewWork := true
|
||||||
for result := range self.recv {
|
for result := range w.recv {
|
||||||
atomic.AddInt32(&self.atWork, -1)
|
atomic.AddInt32(&w.atWork, -1)
|
||||||
|
|
||||||
if result == nil {
|
if result == nil {
|
||||||
continue
|
continue
|
||||||
|
|
@ -317,7 +317,7 @@ func (self *worker) wait() {
|
||||||
for _, log := range work.state.Logs() {
|
for _, log := range work.state.Logs() {
|
||||||
log.BlockHash = block.Hash()
|
log.BlockHash = block.Hash()
|
||||||
}
|
}
|
||||||
stat, err := self.chain.WriteBlockWithState(block, work.receipts, work.state)
|
stat, err := w.chain.WriteBlockWithState(block, work.receipts, work.state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed writing block to chain", "err", err)
|
log.Error("Failed writing block to chain", "err", err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -328,7 +328,7 @@ func (self *worker) wait() {
|
||||||
mustCommitNewWork = false
|
mustCommitNewWork = false
|
||||||
}
|
}
|
||||||
// Broadcast the block and announce chain insertion event
|
// Broadcast the block and announce chain insertion event
|
||||||
self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
w.mux.Post(core.NewMinedBlockEvent{Block: block})
|
||||||
var (
|
var (
|
||||||
events []interface{}
|
events []interface{}
|
||||||
logs = work.state.Logs()
|
logs = work.state.Logs()
|
||||||
|
|
@ -337,25 +337,25 @@ func (self *worker) wait() {
|
||||||
if stat == core.CanonStatTy {
|
if stat == core.CanonStatTy {
|
||||||
events = append(events, core.ChainHeadEvent{Block: block})
|
events = append(events, core.ChainHeadEvent{Block: block})
|
||||||
}
|
}
|
||||||
self.chain.PostChainEvents(events, logs)
|
w.chain.PostChainEvents(events, logs)
|
||||||
|
|
||||||
// Insert the block into the set of pending ones to wait for confirmations
|
// Insert the block into the set of pending ones to wait for confirmations
|
||||||
self.unconfirmed.Insert(block.NumberU64(), block.Hash())
|
w.unconfirmed.Insert(block.NumberU64(), block.Hash())
|
||||||
|
|
||||||
if mustCommitNewWork {
|
if mustCommitNewWork {
|
||||||
self.commitNewWork()
|
w.commitNewWork()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// push sends a new work task to currently live miner agents.
|
// push sends a new work task to currently live miner agents.
|
||||||
func (self *worker) push(work *Work) {
|
func (w *worker) push(work *Work) {
|
||||||
if atomic.LoadInt32(&self.mining) != 1 {
|
if atomic.LoadInt32(&w.mining) != 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for agent := range self.agents {
|
for agent := range w.agents {
|
||||||
atomic.AddInt32(&self.atWork, 1)
|
atomic.AddInt32(&w.atWork, 1)
|
||||||
if ch := agent.Work(); ch != nil {
|
if ch := agent.Work(); ch != nil {
|
||||||
ch <- work
|
ch <- work
|
||||||
}
|
}
|
||||||
|
|
@ -363,14 +363,14 @@ func (self *worker) push(work *Work) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeCurrent creates a new environment for the current cycle.
|
// makeCurrent creates a new environment for the current cycle.
|
||||||
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error {
|
func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
|
||||||
state, err := self.chain.StateAt(parent.Root())
|
state, err := w.chain.StateAt(parent.Root())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
work := &Work{
|
work := &Work{
|
||||||
config: self.config,
|
config: w.config,
|
||||||
signer: types.NewEIP155Signer(self.config.ChainId),
|
signer: types.NewEIP155Signer(w.config.ChainId),
|
||||||
state: state,
|
state: state,
|
||||||
ancestors: set.New(),
|
ancestors: set.New(),
|
||||||
family: set.New(),
|
family: set.New(),
|
||||||
|
|
@ -380,7 +380,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// when 08 is processed ancestors contain 07 (quick block)
|
// when 08 is processed ancestors contain 07 (quick block)
|
||||||
for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
||||||
for _, uncle := range ancestor.Uncles() {
|
for _, uncle := range ancestor.Uncles() {
|
||||||
work.family.Add(uncle.Hash())
|
work.family.Add(uncle.Hash())
|
||||||
}
|
}
|
||||||
|
|
@ -390,20 +390,20 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
|
||||||
|
|
||||||
// Keep track of transactions which return errors so they can be removed
|
// Keep track of transactions which return errors so they can be removed
|
||||||
work.tcount = 0
|
work.tcount = 0
|
||||||
self.current = work
|
w.current = work
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) commitNewWork() {
|
func (w *worker) commitNewWork() {
|
||||||
self.mu.Lock()
|
w.mu.Lock()
|
||||||
defer self.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
self.uncleMu.Lock()
|
w.uncleMu.Lock()
|
||||||
defer self.uncleMu.Unlock()
|
defer w.uncleMu.Unlock()
|
||||||
self.currentMu.Lock()
|
w.currentMu.Lock()
|
||||||
defer self.currentMu.Unlock()
|
defer w.currentMu.Unlock()
|
||||||
|
|
||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
parent := self.chain.CurrentBlock()
|
parent := w.chain.CurrentBlock()
|
||||||
|
|
||||||
tstamp := tstart.Unix()
|
tstamp := tstart.Unix()
|
||||||
if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
|
if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
|
||||||
|
|
@ -421,24 +421,24 @@ func (self *worker) commitNewWork() {
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Number: num.Add(num, common.Big1),
|
Number: num.Add(num, common.Big1),
|
||||||
GasLimit: core.CalcGasLimit(parent),
|
GasLimit: core.CalcGasLimit(parent),
|
||||||
Extra: self.extra,
|
Extra: w.extra,
|
||||||
Time: big.NewInt(tstamp),
|
Time: big.NewInt(tstamp),
|
||||||
}
|
}
|
||||||
// Only set the coinbase if we are mining (avoid spurious block rewards)
|
// Only set the coinbase if we are mining (avoid spurious block rewards)
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&w.mining) == 1 {
|
||||||
header.Coinbase = self.coinbase
|
header.Coinbase = w.coinbase
|
||||||
}
|
}
|
||||||
if err := self.engine.Prepare(self.chain, header); err != nil {
|
if err := w.engine.Prepare(w.chain, header); err != nil {
|
||||||
log.Error("Failed to prepare header for mining", "err", err)
|
log.Error("Failed to prepare header for mining", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// If we are care about TheDAO hard-fork check whether to override the extra-data or not
|
// If we are care about TheDAO hard-fork check whether to override the extra-data or not
|
||||||
if daoBlock := self.config.DAOForkBlock; daoBlock != nil {
|
if daoBlock := w.config.DAOForkBlock; daoBlock != nil {
|
||||||
// Check whether the block is among the fork extra-override range
|
// Check whether the block is among the fork extra-override range
|
||||||
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
|
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
|
||||||
if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 {
|
if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 {
|
||||||
// Depending whether we support or oppose the fork, override differently
|
// Depending whether we support or oppose the fork, override differently
|
||||||
if self.config.DAOForkSupport {
|
if w.config.DAOForkSupport {
|
||||||
header.Extra = common.CopyBytes(params.DAOForkBlockExtra)
|
header.Extra = common.CopyBytes(params.DAOForkBlockExtra)
|
||||||
} else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
} else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
||||||
header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data
|
header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data
|
||||||
|
|
@ -446,34 +446,34 @@ func (self *worker) commitNewWork() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Could potentially happen if starting to mine in an odd state.
|
// Could potentially happen if starting to mine in an odd state.
|
||||||
err := self.makeCurrent(parent, header)
|
err := w.makeCurrent(parent, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to create mining context", "err", err)
|
log.Error("Failed to create mining context", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Create the current work task and check any fork transitions needed
|
// Create the current work task and check any fork transitions needed
|
||||||
work := self.current
|
work := w.current
|
||||||
if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 {
|
if w.config.DAOForkSupport && w.config.DAOForkBlock != nil && w.config.DAOForkBlock.Cmp(header.Number) == 0 {
|
||||||
misc.ApplyDAOHardFork(work.state)
|
misc.ApplyDAOHardFork(work.state)
|
||||||
}
|
}
|
||||||
pending, err := self.eth.TxPool().Pending()
|
pending, err := w.eth.TxPool().Pending()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to fetch pending transactions", "err", err)
|
log.Error("Failed to fetch pending transactions", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
txs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending)
|
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, pending)
|
||||||
work.commitTransactions(self.mux, txs, self.chain, self.coinbase)
|
work.commitTransactions(w.mux, txs, w.chain, w.coinbase)
|
||||||
|
|
||||||
// compute uncles for the new block.
|
// compute uncles for the new block.
|
||||||
var (
|
var (
|
||||||
uncles []*types.Header
|
uncles []*types.Header
|
||||||
badUncles []common.Hash
|
badUncles []common.Hash
|
||||||
)
|
)
|
||||||
for hash, uncle := range self.possibleUncles {
|
for hash, uncle := range w.possibleUncles {
|
||||||
if len(uncles) == 2 {
|
if len(uncles) == 2 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err := self.commitUncle(work, uncle.Header()); err != nil {
|
if err := w.commitUncle(work, uncle.Header()); err != nil {
|
||||||
log.Trace("Bad uncle found and will be removed", "hash", hash)
|
log.Trace("Bad uncle found and will be removed", "hash", hash)
|
||||||
log.Trace(fmt.Sprint(uncle))
|
log.Trace(fmt.Sprint(uncle))
|
||||||
|
|
||||||
|
|
@ -484,23 +484,23 @@ func (self *worker) commitNewWork() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, hash := range badUncles {
|
for _, hash := range badUncles {
|
||||||
delete(self.possibleUncles, hash)
|
delete(w.possibleUncles, hash)
|
||||||
}
|
}
|
||||||
// Create the new block to seal with the consensus engine
|
// Create the new block to seal with the consensus engine
|
||||||
if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, uncles, work.receipts); err != nil {
|
if work.Block, err = w.engine.Finalize(w.chain, header, work.state, work.txs, uncles, work.receipts); err != nil {
|
||||||
log.Error("Failed to finalize block for sealing", "err", err)
|
log.Error("Failed to finalize block for sealing", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// We only care about logging if we're actually mining.
|
// We only care about logging if we're actually mining.
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&w.mining) == 1 {
|
||||||
log.Info("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart)))
|
log.Info("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart)))
|
||||||
self.unconfirmed.Shift(work.Block.NumberU64() - 1)
|
w.unconfirmed.Shift(work.Block.NumberU64() - 1)
|
||||||
}
|
}
|
||||||
self.push(work)
|
w.push(work)
|
||||||
self.updateSnapshot()
|
w.updateSnapshot()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
|
func (w *worker) commitUncle(work *Work, uncle *types.Header) error {
|
||||||
hash := uncle.Hash()
|
hash := uncle.Hash()
|
||||||
if work.uncles.Has(hash) {
|
if work.uncles.Has(hash) {
|
||||||
return fmt.Errorf("uncle not unique")
|
return fmt.Errorf("uncle not unique")
|
||||||
|
|
@ -515,17 +515,17 @@ func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *worker) updateSnapshot() {
|
func (w *worker) updateSnapshot() {
|
||||||
self.snapshotMu.Lock()
|
w.snapshotMu.Lock()
|
||||||
defer self.snapshotMu.Unlock()
|
defer w.snapshotMu.Unlock()
|
||||||
|
|
||||||
self.snapshotBlock = types.NewBlock(
|
w.snapshotBlock = types.NewBlock(
|
||||||
self.current.header,
|
w.current.header,
|
||||||
self.current.txs,
|
w.current.txs,
|
||||||
nil,
|
nil,
|
||||||
self.current.receipts,
|
w.current.receipts,
|
||||||
)
|
)
|
||||||
self.snapshotState = self.current.state.Copy()
|
w.snapshotState = w.current.state.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address) {
|
func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address) {
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,8 @@ type Api struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//the api constructor initialises
|
//the api constructor initialises
|
||||||
func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) {
|
func NewApi(dpa *storage.DPA, dns Resolver) (api *Api) {
|
||||||
self = &Api{
|
api = &Api{
|
||||||
dpa: dpa,
|
dpa: dpa,
|
||||||
dns: dns,
|
dns: dns,
|
||||||
}
|
}
|
||||||
|
|
@ -156,25 +156,25 @@ func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// to be used only in TEST
|
// to be used only in TEST
|
||||||
func (self *Api) Upload(uploadDir, index string) (hash string, err error) {
|
func (api *Api) Upload(uploadDir, index string) (hash string, err error) {
|
||||||
fs := NewFileSystem(self)
|
fs := NewFileSystem(api)
|
||||||
hash, err = fs.Upload(uploadDir, index)
|
hash, err = fs.Upload(uploadDir, index)
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DPA reader API
|
// DPA reader API
|
||||||
func (self *Api) Retrieve(key storage.Key) storage.LazySectionReader {
|
func (api *Api) Retrieve(key storage.Key) storage.LazySectionReader {
|
||||||
return self.dpa.Retrieve(key)
|
return api.dpa.Retrieve(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
|
func (api *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
|
||||||
return self.dpa.Store(data, size, wg, nil)
|
return api.dpa.Store(data, size, wg, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrResolve error
|
type ErrResolve error
|
||||||
|
|
||||||
// DNS Resolver
|
// DNS Resolver
|
||||||
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
func (api *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
apiResolveCount.Inc(1)
|
apiResolveCount.Inc(1)
|
||||||
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if DNS is not configured, check if the address is a hash
|
// if DNS is not configured, check if the address is a hash
|
||||||
if self.dns == nil {
|
if api.dns == nil {
|
||||||
if !isHash {
|
if !isHash {
|
||||||
apiResolveFail.Inc(1)
|
apiResolveFail.Inc(1)
|
||||||
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
||||||
|
|
@ -197,7 +197,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try and resolve the address
|
// try and resolve the address
|
||||||
resolved, err := self.dns.Resolve(uri.Addr)
|
resolved, err := api.dns.Resolve(uri.Addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return resolved[:], nil
|
return resolved[:], nil
|
||||||
} else if !isHash {
|
} else if !isHash {
|
||||||
|
|
@ -208,18 +208,18 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put provides singleton manifest creation on top of dpa store
|
// Put provides singleton manifest creation on top of dpa store
|
||||||
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
func (api *Api) Put(content, contentType string) (storage.Key, error) {
|
||||||
apiPutCount.Inc(1)
|
apiPutCount.Inc(1)
|
||||||
r := strings.NewReader(content)
|
r := strings.NewReader(content)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
|
key, err := api.dpa.Store(r, int64(len(content)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiPutFail.Inc(1)
|
apiPutFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
||||||
r = strings.NewReader(manifest)
|
r = strings.NewReader(manifest)
|
||||||
key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
|
key, err = api.dpa.Store(r, int64(len(manifest)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiPutFail.Inc(1)
|
apiPutFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -231,9 +231,9 @@ func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
||||||
// Get uses iterative manifest retrieval and prefix matching
|
// Get uses iterative manifest retrieval and prefix matching
|
||||||
// to resolve basePath to content using dpa retrieve
|
// to resolve basePath to content using dpa retrieve
|
||||||
// it returns a section reader, mimeType, status and an error
|
// it returns a section reader, mimeType, status and an error
|
||||||
func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
func (api *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
||||||
apiGetCount.Inc(1)
|
apiGetCount.Inc(1)
|
||||||
trie, err := loadManifest(self.dpa, key, nil)
|
trie, err := loadManifest(api.dpa, key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
|
|
@ -254,7 +254,7 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
||||||
} else {
|
} else {
|
||||||
mimeType = entry.ContentType
|
mimeType = entry.ContentType
|
||||||
log.Trace(fmt.Sprintf("content lookup key: '%v' (%v)", key, mimeType))
|
log.Trace(fmt.Sprintf("content lookup key: '%v' (%v)", key, mimeType))
|
||||||
reader = self.dpa.Retrieve(key)
|
reader = api.dpa.Retrieve(key)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
|
|
@ -265,10 +265,10 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
func (api *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
||||||
apiModifyCount.Inc(1)
|
apiModifyCount.Inc(1)
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
trie, err := loadManifest(self.dpa, key, quitC)
|
trie, err := loadManifest(api.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiModifyFail.Inc(1)
|
apiModifyFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -291,7 +291,7 @@ func (self *Api) Modify(key storage.Key, path, contentHash, contentType string)
|
||||||
return trie.hash, nil
|
return trie.hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) {
|
func (api *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) {
|
||||||
apiAddFileCount.Inc(1)
|
apiAddFileCount.Inc(1)
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
|
|
@ -299,7 +299,7 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
||||||
apiAddFileFail.Inc(1)
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAddFileFail.Inc(1)
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -318,7 +318,7 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
||||||
ModTime: time.Now(),
|
ModTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := api.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAddFileFail.Inc(1)
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -341,7 +341,7 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) {
|
func (api *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) {
|
||||||
apiRmFileCount.Inc(1)
|
apiRmFileCount.Inc(1)
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
|
|
@ -349,7 +349,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
||||||
apiRmFileFail.Inc(1)
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiRmFileFail.Inc(1)
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -360,7 +360,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := api.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiRmFileFail.Inc(1)
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -382,7 +382,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
||||||
return newMkey.String(), nil
|
return newMkey.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) {
|
func (api *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) {
|
||||||
apiAppendFileCount.Inc(1)
|
apiAppendFileCount.Inc(1)
|
||||||
|
|
||||||
buffSize := offset + addSize
|
buffSize := offset + addSize
|
||||||
|
|
@ -392,7 +392,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
|
|
||||||
buf := make([]byte, buffSize)
|
buf := make([]byte, buffSize)
|
||||||
|
|
||||||
oldReader := self.Retrieve(oldKey)
|
oldReader := api.Retrieve(oldKey)
|
||||||
io.ReadAtLeast(oldReader, buf, int(offset))
|
io.ReadAtLeast(oldReader, buf, int(offset))
|
||||||
|
|
||||||
newReader := bytes.NewReader(content)
|
newReader := bytes.NewReader(content)
|
||||||
|
|
@ -406,7 +406,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
totalSize := int64(len(buf))
|
totalSize := int64(len(buf))
|
||||||
|
|
||||||
// TODO(jmozah): to append using pyramid chunker when it is ready
|
// TODO(jmozah): to append using pyramid chunker when it is ready
|
||||||
//oldReader := self.Retrieve(oldKey)
|
//oldReader := api.Retrieve(oldKey)
|
||||||
//newReader := bytes.NewReader(content)
|
//newReader := bytes.NewReader(content)
|
||||||
//combinedReader := io.MultiReader(oldReader, newReader)
|
//combinedReader := io.MultiReader(oldReader, newReader)
|
||||||
|
|
||||||
|
|
@ -415,7 +415,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
apiAppendFileFail.Inc(1)
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAppendFileFail.Inc(1)
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -426,7 +426,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := api.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAppendFileFail.Inc(1)
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -463,19 +463,19 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) {
|
func (api *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) {
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
key, err = self.Resolve(uri)
|
key, err = api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
rootTrie, err := loadManifest(self.dpa, key, quitC)
|
rootTrie, err := loadManifest(api.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("can't load manifest %v: %v", key.String(), err)
|
return nil, nil, fmt.Errorf("can't load manifest %v: %v", key.String(), err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,9 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//create a default config with all parameters to set to defaults
|
//create a default config with all parameters to set to defaults
|
||||||
func NewDefaultConfig() (self *Config) {
|
func NewDefaultConfig() (cfg *Config) {
|
||||||
|
|
||||||
self = &Config{
|
cfg = &Config{
|
||||||
StoreParams: storage.NewDefaultStoreParams(),
|
StoreParams: storage.NewDefaultStoreParams(),
|
||||||
ChunkerParams: storage.NewChunkerParams(),
|
ChunkerParams: storage.NewChunkerParams(),
|
||||||
HiveParams: network.NewDefaultHiveParams(),
|
HiveParams: network.NewDefaultHiveParams(),
|
||||||
|
|
@ -89,11 +89,11 @@ func NewDefaultConfig() (self *Config) {
|
||||||
|
|
||||||
//some config params need to be initialized after the complete
|
//some config params need to be initialized after the complete
|
||||||
//config building phase is completed (e.g. due to overriding flags)
|
//config building phase is completed (e.g. due to overriding flags)
|
||||||
func (self *Config) Init(prvKey *ecdsa.PrivateKey) {
|
func (cfg *Config) Init(prvKey *ecdsa.PrivateKey) {
|
||||||
|
|
||||||
address := crypto.PubkeyToAddress(prvKey.PublicKey)
|
address := crypto.PubkeyToAddress(prvKey.PublicKey)
|
||||||
self.Path = filepath.Join(self.Path, "bzz-"+common.Bytes2Hex(address.Bytes()))
|
cfg.Path = filepath.Join(cfg.Path, "bzz-"+common.Bytes2Hex(address.Bytes()))
|
||||||
err := os.MkdirAll(self.Path, os.ModePerm)
|
err := os.MkdirAll(cfg.Path, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("Error creating root swarm data directory: %v", err))
|
log.Error(fmt.Sprintf("Error creating root swarm data directory: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -103,11 +103,11 @@ func (self *Config) Init(prvKey *ecdsa.PrivateKey) {
|
||||||
pubkeyhex := common.ToHex(pubkey)
|
pubkeyhex := common.ToHex(pubkey)
|
||||||
keyhex := crypto.Keccak256Hash(pubkey).Hex()
|
keyhex := crypto.Keccak256Hash(pubkey).Hex()
|
||||||
|
|
||||||
self.PublicKey = pubkeyhex
|
cfg.PublicKey = pubkeyhex
|
||||||
self.BzzKey = keyhex
|
cfg.BzzKey = keyhex
|
||||||
|
|
||||||
self.Swap.Init(self.Contract, prvKey)
|
cfg.Swap.Init(cfg.Contract, prvKey)
|
||||||
self.SyncParams.Init(self.Path)
|
cfg.SyncParams.Init(cfg.Path)
|
||||||
self.HiveParams.Init(self.Path)
|
cfg.HiveParams.Init(cfg.Path)
|
||||||
self.StoreParams.Init(self.Path)
|
cfg.StoreParams.Init(cfg.Path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func NewFileSystem(api *Api) *FileSystem {
|
||||||
// TODO: localpath should point to a manifest
|
// TODO: localpath should point to a manifest
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
func (fs *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
var list []*manifestTrieEntry
|
var list []*manifestTrieEntry
|
||||||
localpath, err := filepath.Abs(filepath.Clean(lpath))
|
localpath, err := filepath.Abs(filepath.Clean(lpath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -113,7 +113,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
stat, _ := f.Stat()
|
stat, _ := f.Stat()
|
||||||
var hash storage.Key
|
var hash storage.Key
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
hash, err = self.api.dpa.Store(f, stat.Size(), wg, nil)
|
hash, err = fs.api.dpa.Store(f, stat.Size(), wg, nil)
|
||||||
if hash != nil {
|
if hash != nil {
|
||||||
list[i].Hash = hash.String()
|
list[i].Hash = hash.String()
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +142,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
trie := &manifestTrie{
|
trie := &manifestTrie{
|
||||||
dpa: self.api.dpa,
|
dpa: fs.api.dpa,
|
||||||
}
|
}
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
for i, entry := range list {
|
for i, entry := range list {
|
||||||
|
|
@ -173,7 +173,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
// under localpath
|
// under localpath
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *FileSystem) Download(bzzpath, localpath string) error {
|
func (fs *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
lpath, err := filepath.Abs(filepath.Clean(localpath))
|
lpath, err := filepath.Abs(filepath.Clean(localpath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -188,7 +188,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key, err := self.api.Resolve(uri)
|
key, err := fs.api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +199,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
trie, err := loadManifest(self.api.dpa, key, quitC)
|
trie, err := loadManifest(fs.api.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err))
|
log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err))
|
||||||
return err
|
return err
|
||||||
|
|
@ -244,7 +244,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
}
|
}
|
||||||
go func(i int, entry *downloadListEntry) {
|
go func(i int, entry *downloadListEntry) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
err := retrieveToFile(quitC, self.api.dpa, entry.key, entry.path)
|
err := retrieveToFile(quitC, fs.api.dpa, entry.key, entry.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
select {
|
||||||
case errC <- err:
|
case errC <- err:
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,12 @@ type RoundTripper struct {
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
func (tripper *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||||
host := self.Host
|
host := tripper.Host
|
||||||
if len(host) == 0 {
|
if len(host) == 0 {
|
||||||
host = "localhost"
|
host = "localhost"
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("http://%s:%s/%s:/%s/%s", host, self.Port, req.Proto, req.URL.Host, req.URL.Path)
|
url := fmt.Sprintf("http://%s:%s/%s:/%s/%s", host, tripper.Port, req.Proto, req.URL.Host, req.URL.Path)
|
||||||
log.Info(fmt.Sprintf("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url))
|
log.Info(fmt.Sprintf("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url))
|
||||||
reqProxy, err := http.NewRequest(req.Method, url, req.Body)
|
reqProxy, err := http.NewRequest(req.Method, url, req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -230,18 +230,18 @@ func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
func (trie *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
||||||
self.hash = nil // trie modified, hash needs to be re-calculated on demand
|
trie.hash = nil // trie modified, hash needs to be re-calculated on demand
|
||||||
|
|
||||||
if len(entry.Path) == 0 {
|
if len(entry.Path) == 0 {
|
||||||
self.entries[256] = entry
|
trie.entries[256] = entry
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b := entry.Path[0]
|
b := entry.Path[0]
|
||||||
oldentry := self.entries[b]
|
oldentry := trie.entries[b]
|
||||||
if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) {
|
if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) {
|
||||||
self.entries[b] = entry
|
trie.entries[b] = entry
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,7 +251,7 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) {
|
if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) {
|
||||||
if self.loadSubTrie(oldentry, quitC) != nil {
|
if trie.loadSubTrie(oldentry, quitC) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entry.Path = entry.Path[cpl:]
|
entry.Path = entry.Path[cpl:]
|
||||||
|
|
@ -263,21 +263,21 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
||||||
commonPrefix := entry.Path[:cpl]
|
commonPrefix := entry.Path[:cpl]
|
||||||
|
|
||||||
subtrie := &manifestTrie{
|
subtrie := &manifestTrie{
|
||||||
dpa: self.dpa,
|
dpa: trie.dpa,
|
||||||
}
|
}
|
||||||
entry.Path = entry.Path[cpl:]
|
entry.Path = entry.Path[cpl:]
|
||||||
oldentry.Path = oldentry.Path[cpl:]
|
oldentry.Path = oldentry.Path[cpl:]
|
||||||
subtrie.addEntry(entry, quitC)
|
subtrie.addEntry(entry, quitC)
|
||||||
subtrie.addEntry(oldentry, quitC)
|
subtrie.addEntry(oldentry, quitC)
|
||||||
|
|
||||||
self.entries[b] = newManifestTrieEntry(&ManifestEntry{
|
trie.entries[b] = newManifestTrieEntry(&ManifestEntry{
|
||||||
Path: commonPrefix,
|
Path: commonPrefix,
|
||||||
ContentType: ManifestType,
|
ContentType: ManifestType,
|
||||||
}, subtrie)
|
}, subtrie)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
|
func (trie *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
|
||||||
for _, e := range self.entries {
|
for _, e := range trie.entries {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
cnt++
|
cnt++
|
||||||
entry = e
|
entry = e
|
||||||
|
|
@ -286,27 +286,27 @@ func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) deleteEntry(path string, quitC chan bool) {
|
func (trie *manifestTrie) deleteEntry(path string, quitC chan bool) {
|
||||||
self.hash = nil // trie modified, hash needs to be re-calculated on demand
|
trie.hash = nil // trie modified, hash needs to be re-calculated on demand
|
||||||
|
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
self.entries[256] = nil
|
trie.entries[256] = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b := path[0]
|
b := path[0]
|
||||||
entry := self.entries[b]
|
entry := trie.entries[b]
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if entry.Path == path {
|
if entry.Path == path {
|
||||||
self.entries[b] = nil
|
trie.entries[b] = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
epl := len(entry.Path)
|
epl := len(entry.Path)
|
||||||
if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) {
|
if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) {
|
||||||
if self.loadSubTrie(entry, quitC) != nil {
|
if trie.loadSubTrie(entry, quitC) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entry.subtrie.deleteEntry(path[epl:], quitC)
|
entry.subtrie.deleteEntry(path[epl:], quitC)
|
||||||
|
|
@ -317,13 +317,13 @@ func (self *manifestTrie) deleteEntry(path string, quitC chan bool) {
|
||||||
if lastentry != nil {
|
if lastentry != nil {
|
||||||
lastentry.Path = entry.Path + lastentry.Path
|
lastentry.Path = entry.Path + lastentry.Path
|
||||||
}
|
}
|
||||||
self.entries[b] = lastentry
|
trie.entries[b] = lastentry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) recalcAndStore() error {
|
func (trie *manifestTrie) recalcAndStore() error {
|
||||||
if self.hash != nil {
|
if trie.hash != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +331,7 @@ func (self *manifestTrie) recalcAndStore() error {
|
||||||
buffer.WriteString(`{"entries":[`)
|
buffer.WriteString(`{"entries":[`)
|
||||||
|
|
||||||
list := &Manifest{}
|
list := &Manifest{}
|
||||||
for _, entry := range self.entries {
|
for _, entry := range trie.entries {
|
||||||
if entry != nil {
|
if entry != nil {
|
||||||
if entry.Hash == "" { // TODO: paralellize
|
if entry.Hash == "" { // TODO: paralellize
|
||||||
err := entry.subtrie.recalcAndStore()
|
err := entry.subtrie.recalcAndStore()
|
||||||
|
|
@ -352,22 +352,22 @@ func (self *manifestTrie) recalcAndStore() error {
|
||||||
|
|
||||||
sr := bytes.NewReader(manifest)
|
sr := bytes.NewReader(manifest)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg, nil)
|
key, err2 := trie.dpa.Store(sr, int64(len(manifest)), wg, nil)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
self.hash = key
|
trie.hash = key
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
|
func (trie *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
|
||||||
if entry.subtrie == nil {
|
if entry.subtrie == nil {
|
||||||
hash := common.Hex2Bytes(entry.Hash)
|
hash := common.Hex2Bytes(entry.Hash)
|
||||||
entry.subtrie, err = loadManifest(self.dpa, hash, quitC)
|
entry.subtrie, err = loadManifest(trie.dpa, hash, quitC)
|
||||||
entry.Hash = "" // might not match, should be recalculated
|
entry.Hash = "" // might not match, should be recalculated
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
|
func (trie *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
|
||||||
plen := len(prefix)
|
plen := len(prefix)
|
||||||
var start, stop int
|
var start, stop int
|
||||||
if plen == 0 {
|
if plen == 0 {
|
||||||
|
|
@ -384,7 +384,7 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool,
|
||||||
return fmt.Errorf("aborted")
|
return fmt.Errorf("aborted")
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
entry := self.entries[i]
|
entry := trie.entries[i]
|
||||||
if entry != nil {
|
if entry != nil {
|
||||||
epl := len(entry.Path)
|
epl := len(entry.Path)
|
||||||
if entry.ContentType == ManifestType {
|
if entry.ContentType == ManifestType {
|
||||||
|
|
@ -393,7 +393,7 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool,
|
||||||
l = epl
|
l = epl
|
||||||
}
|
}
|
||||||
if prefix[:l] == entry.Path[:l] {
|
if prefix[:l] == entry.Path[:l] {
|
||||||
err := self.loadSubTrie(entry, quitC)
|
err := trie.loadSubTrie(entry, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -412,23 +412,23 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
|
func (trie *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
|
||||||
return self.listWithPrefixInt(prefix, "", quitC, cb)
|
return trie.listWithPrefixInt(prefix, "", quitC, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
|
func (trie *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
|
||||||
|
|
||||||
log.Trace(fmt.Sprintf("findPrefixOf(%s)", path))
|
log.Trace(fmt.Sprintf("findPrefixOf(%s)", path))
|
||||||
|
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
return self.entries[256], 0
|
return trie.entries[256], 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//see if first char is in manifest entries
|
//see if first char is in manifest entries
|
||||||
b := path[0]
|
b := path[0]
|
||||||
entry = self.entries[b]
|
entry = trie.entries[b]
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return self.entries[256], 0
|
return trie.entries[256], 0
|
||||||
}
|
}
|
||||||
|
|
||||||
epl := len(entry.Path)
|
epl := len(entry.Path)
|
||||||
|
|
@ -436,7 +436,7 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man
|
||||||
if len(path) <= epl {
|
if len(path) <= epl {
|
||||||
if entry.Path[:len(path)] == path {
|
if entry.Path[:len(path)] == path {
|
||||||
if entry.ContentType == ManifestType {
|
if entry.ContentType == ManifestType {
|
||||||
err := self.loadSubTrie(entry, quitC)
|
err := trie.loadSubTrie(entry, quitC)
|
||||||
if err == nil && entry.subtrie != nil {
|
if err == nil && entry.subtrie != nil {
|
||||||
subentries := entry.subtrie.entries
|
subentries := entry.subtrie.entries
|
||||||
for i := 0; i < len(subentries); i++ {
|
for i := 0; i < len(subentries); i++ {
|
||||||
|
|
@ -457,7 +457,7 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man
|
||||||
log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType))
|
log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType))
|
||||||
//the subentry is a manifest, load subtrie
|
//the subentry is a manifest, load subtrie
|
||||||
if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) {
|
if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) {
|
||||||
err := self.loadSubTrie(entry, quitC)
|
err := trie.loadSubTrie(entry, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
|
@ -495,10 +495,10 @@ func RegularSlashes(path string) (res string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
|
func (trie *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
|
||||||
path := RegularSlashes(spath)
|
path := RegularSlashes(spath)
|
||||||
var pos int
|
var pos int
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
entry, pos = self.findPrefixOf(path, quitC)
|
entry, pos = trie.findPrefixOf(path, quitC)
|
||||||
return entry, path[:pos]
|
return entry, path[:pos]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ func NewStorage(api *Api) *Storage {
|
||||||
// its content type
|
// its content type
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *Storage) Put(content, contentType string) (string, error) {
|
func (s *Storage) Put(content, contentType string) (string, error) {
|
||||||
key, err := self.api.Put(content, contentType)
|
key, err := s.api.Put(content, contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -57,16 +57,16 @@ func (self *Storage) Put(content, contentType string) (string, error) {
|
||||||
// size is resp.Size
|
// size is resp.Size
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *Storage) Get(bzzpath string) (*Response, error) {
|
func (s *Storage) Get(bzzpath string) (*Response, error) {
|
||||||
uri, err := Parse(path.Join("bzz:/", bzzpath))
|
uri, err := Parse(path.Join("bzz:/", bzzpath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
key, err := self.api.Resolve(uri)
|
key, err := s.api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader, mimeType, status, err := self.api.Get(key, uri.Path)
|
reader, mimeType, status, err := s.api.Get(key, uri.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -87,16 +87,16 @@ func (self *Storage) Get(bzzpath string) (*Response, error) {
|
||||||
// and merge on to it. creating an entry w conentType (mime)
|
// and merge on to it. creating an entry w conentType (mime)
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *Storage) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) {
|
func (s *Storage) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) {
|
||||||
uri, err := Parse("bzz:/" + rootHash)
|
uri, err := Parse("bzz:/" + rootHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
key, err := self.api.Resolve(uri)
|
key, err := s.api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
key, err = self.api.Modify(key, path, contentHash, contentType)
|
key, err = s.api.Modify(key, path, contentHash, contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,18 +29,18 @@ func NewControl(api *Api, hive *network.Hive) *Control {
|
||||||
return &Control{api, hive}
|
return &Control{api, hive}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) BlockNetworkRead(on bool) {
|
func (c *Control) BlockNetworkRead(on bool) {
|
||||||
self.hive.BlockNetworkRead(on)
|
c.hive.BlockNetworkRead(on)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) SyncEnabled(on bool) {
|
func (c *Control) SyncEnabled(on bool) {
|
||||||
self.hive.SyncEnabled(on)
|
c.hive.SyncEnabled(on)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) SwapEnabled(on bool) {
|
func (c *Control) SwapEnabled(on bool) {
|
||||||
self.hive.SwapEnabled(on)
|
c.hive.SwapEnabled(on)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) Hive() string {
|
func (c *Control) Hive() string {
|
||||||
return self.hive.String()
|
return c.hive.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,18 +34,18 @@ type MountInfo struct {
|
||||||
LatestManifest string
|
LatestManifest string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
func (fs *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
return nil, errNoFUSE
|
return nil, errNoFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Unmount(mountpoint string) (bool, error) {
|
func (fs *SwarmFS) Unmount(mountpoint string) (bool, error) {
|
||||||
return false, errNoFUSE
|
return false, errNoFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Listmounts() ([]*MountInfo, error) {
|
func (fs *SwarmFS) Listmounts() ([]*MountInfo, error) {
|
||||||
return nil, errNoFUSE
|
return nil, errNoFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Stop() error {
|
func (fs *SwarmFS) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ func NewMountInfo(mhash, mpoint string, sapi *api.Api) *MountInfo {
|
||||||
return newMountInfo
|
return newMountInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
func (s *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
|
|
||||||
if mountpoint == "" {
|
if mountpoint == "" {
|
||||||
return nil, errEmptyMountPoint
|
return nil, errEmptyMountPoint
|
||||||
|
|
@ -82,25 +82,25 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
self.swarmFsLock.Lock()
|
s.swarmFsLock.Lock()
|
||||||
defer self.swarmFsLock.Unlock()
|
defer s.swarmFsLock.Unlock()
|
||||||
|
|
||||||
noOfActiveMounts := len(self.activeMounts)
|
noOfActiveMounts := len(s.activeMounts)
|
||||||
if noOfActiveMounts >= maxFuseMounts {
|
if noOfActiveMounts >= maxFuseMounts {
|
||||||
return nil, errMaxMountCount
|
return nil, errMaxMountCount
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := self.activeMounts[cleanedMountPoint]; ok {
|
if _, ok := s.activeMounts[cleanedMountPoint]; ok {
|
||||||
return nil, errAlreadyMounted
|
return nil, errAlreadyMounted
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint))
|
log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint))
|
||||||
_, manifestEntryMap, err := self.swarmApi.BuildDirectoryTree(mhash, true)
|
_, manifestEntryMap, err := s.swarmApi.BuildDirectoryTree(mhash, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mi := NewMountInfo(mhash, cleanedMountPoint, self.swarmApi)
|
mi := NewMountInfo(mhash, cleanedMountPoint, s.swarmApi)
|
||||||
|
|
||||||
dirTree := map[string]*SwarmDir{}
|
dirTree := map[string]*SwarmDir{}
|
||||||
rootDir := NewSwarmDir("/", mi)
|
rootDir := NewSwarmDir("/", mi)
|
||||||
|
|
@ -174,21 +174,21 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
log.Info("Now serving swarm FUSE FS", "manifest", mhash, "mountpoint", cleanedMountPoint)
|
log.Info("Now serving swarm FUSE FS", "manifest", mhash, "mountpoint", cleanedMountPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.activeMounts[cleanedMountPoint] = mi
|
s.activeMounts[cleanedMountPoint] = mi
|
||||||
return mi, nil
|
return mi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
func (s *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
||||||
|
|
||||||
self.swarmFsLock.Lock()
|
s.swarmFsLock.Lock()
|
||||||
defer self.swarmFsLock.Unlock()
|
defer s.swarmFsLock.Unlock()
|
||||||
|
|
||||||
cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
|
cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mountInfo := self.activeMounts[cleanedMountPoint]
|
mountInfo := s.activeMounts[cleanedMountPoint]
|
||||||
|
|
||||||
if mountInfo == nil || mountInfo.MountPoint != cleanedMountPoint {
|
if mountInfo == nil || mountInfo.MountPoint != cleanedMountPoint {
|
||||||
return nil, fmt.Errorf("%s is not mounted", cleanedMountPoint)
|
return nil, fmt.Errorf("%s is not mounted", cleanedMountPoint)
|
||||||
|
|
@ -204,7 +204,7 @@ func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mountInfo.fuseConnection.Close()
|
mountInfo.fuseConnection.Close()
|
||||||
delete(self.activeMounts, cleanedMountPoint)
|
delete(s.activeMounts, cleanedMountPoint)
|
||||||
|
|
||||||
succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint)
|
succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint)
|
||||||
log.Info(succString)
|
log.Info(succString)
|
||||||
|
|
@ -212,21 +212,21 @@ func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
||||||
return mountInfo, nil
|
return mountInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Listmounts() []*MountInfo {
|
func (s *SwarmFS) Listmounts() []*MountInfo {
|
||||||
self.swarmFsLock.RLock()
|
s.swarmFsLock.RLock()
|
||||||
defer self.swarmFsLock.RUnlock()
|
defer s.swarmFsLock.RUnlock()
|
||||||
|
|
||||||
rows := make([]*MountInfo, 0, len(self.activeMounts))
|
rows := make([]*MountInfo, 0, len(s.activeMounts))
|
||||||
for _, mi := range self.activeMounts {
|
for _, mi := range s.activeMounts {
|
||||||
rows = append(rows, mi)
|
rows = append(rows, mi)
|
||||||
}
|
}
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Stop() bool {
|
func (s *SwarmFS) Stop() bool {
|
||||||
for mp := range self.activeMounts {
|
for mp := range s.activeMounts {
|
||||||
mountInfo := self.activeMounts[mp]
|
mountInfo := s.activeMounts[mp]
|
||||||
self.Unmount(mountInfo.MountPoint)
|
s.Unmount(mountInfo.MountPoint)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,14 +58,14 @@ func NewDepo(hash storage.SwarmHasher, localStore, remoteStore storage.ChunkStor
|
||||||
// * back immediately as a deliveryRequest message
|
// * back immediately as a deliveryRequest message
|
||||||
// * empty message just pings back for more (is this needed?)
|
// * empty message just pings back for more (is this needed?)
|
||||||
// * strict signed sync states may be needed.
|
// * strict signed sync states may be needed.
|
||||||
func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error {
|
func (d *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error {
|
||||||
unsynced := req.Unsynced
|
unsynced := req.Unsynced
|
||||||
var missing []*syncRequest
|
var missing []*syncRequest
|
||||||
var chunk *storage.Chunk
|
var chunk *storage.Chunk
|
||||||
var err error
|
var err error
|
||||||
for _, req := range unsynced {
|
for _, req := range unsynced {
|
||||||
// skip keys that are found,
|
// skip keys that are found,
|
||||||
chunk, err = self.localStore.Get(req.Key[:])
|
chunk, err = d.localStore.Get(req.Key[:])
|
||||||
if err != nil || chunk.SData == nil {
|
if err != nil || chunk.SData == nil {
|
||||||
missing = append(missing, req)
|
missing = append(missing, req)
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,7 @@ func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error
|
||||||
// (remote peer is free to reprioritize)
|
// (remote peer is free to reprioritize)
|
||||||
// * the message implies remote peer wants more, so trigger for
|
// * the message implies remote peer wants more, so trigger for
|
||||||
// * new outgoing unsynced keys message is fired
|
// * new outgoing unsynced keys message is fired
|
||||||
func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error {
|
func (d *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error {
|
||||||
deliver := req.Deliver
|
deliver := req.Deliver
|
||||||
// queue the actual delivery of a chunk ()
|
// queue the actual delivery of a chunk ()
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver))
|
log.Trace(fmt.Sprintf("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver))
|
||||||
|
|
@ -96,7 +96,7 @@ func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer)
|
||||||
// TODO: look up in cache here or in deliveries
|
// TODO: look up in cache here or in deliveries
|
||||||
// priorities are taken from the message so the remote party can
|
// priorities are taken from the message so the remote party can
|
||||||
// reprioritise to at their leisure
|
// reprioritise to at their leisure
|
||||||
// r = self.pullCached(sreq.Key) // pulls and deletes from cache
|
// r = d.pullCached(sreq.Key) // pulls and deletes from cache
|
||||||
Push(p, sreq.Key, sreq.Priority)
|
Push(p, sreq.Key, sreq.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,10 +108,10 @@ func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer)
|
||||||
// the entrypoint for store requests coming from the bzz wire protocol
|
// the entrypoint for store requests coming from the bzz wire protocol
|
||||||
// if key found locally, return. otherwise
|
// if key found locally, return. otherwise
|
||||||
// remote is untrusted, so hash is verified and chunk passed on to NetStore
|
// remote is untrusted, so hash is verified and chunk passed on to NetStore
|
||||||
func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
func (d *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
||||||
var islocal bool
|
var islocal bool
|
||||||
req.from = p
|
req.from = p
|
||||||
chunk, err := self.localStore.Get(req.Key)
|
chunk, err := d.localStore.Get(req.Key)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
|
log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
|
||||||
|
|
@ -133,7 +133,7 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
||||||
//return
|
//return
|
||||||
}
|
}
|
||||||
|
|
||||||
hasher := self.hashfunc()
|
hasher := d.hashfunc()
|
||||||
hasher.Write(req.SData)
|
hasher.Write(req.SData)
|
||||||
if !bytes.Equal(hasher.Sum(nil), req.Key) {
|
if !bytes.Equal(hasher.Sum(nil), req.Key) {
|
||||||
// data does not validate, ignore
|
// data does not validate, ignore
|
||||||
|
|
@ -150,12 +150,12 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
||||||
chunk.Size = int64(binary.LittleEndian.Uint64(req.SData[0:8]))
|
chunk.Size = int64(binary.LittleEndian.Uint64(req.SData[0:8]))
|
||||||
log.Trace(fmt.Sprintf("delivery of %v from %v", chunk, p))
|
log.Trace(fmt.Sprintf("delivery of %v from %v", chunk, p))
|
||||||
chunk.Source = p
|
chunk.Source = p
|
||||||
self.netStore.Put(chunk)
|
d.netStore.Put(chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// entrypoint for retrieve requests coming from the bzz wire protocol
|
// entrypoint for retrieve requests coming from the bzz wire protocol
|
||||||
// checks swap balance - return if peer has no credit
|
// checks swap balance - return if peer has no credit
|
||||||
func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) {
|
func (d *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) {
|
||||||
req.from = p
|
req.from = p
|
||||||
// swap - record credit for 1 request
|
// swap - record credit for 1 request
|
||||||
// note that only charge actual reqsearches
|
// note that only charge actual reqsearches
|
||||||
|
|
@ -171,8 +171,8 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
|
||||||
// call storage.NetStore#Get which
|
// call storage.NetStore#Get which
|
||||||
// blocks until local retrieval finished
|
// blocks until local retrieval finished
|
||||||
// launches cloud retrieval
|
// launches cloud retrieval
|
||||||
chunk, _ := self.netStore.Get(req.Key)
|
chunk, _ := d.netStore.Get(req.Key)
|
||||||
req = self.strategyUpdateRequest(chunk.Req, req)
|
req = d.strategyUpdateRequest(chunk.Req, req)
|
||||||
// check if we can immediately deliver
|
// check if we can immediately deliver
|
||||||
if chunk.SData != nil {
|
if chunk.SData != nil {
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log()))
|
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log()))
|
||||||
|
|
@ -197,20 +197,20 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add peer request the chunk and decides the timeout for the response if still searching
|
// add peer request the chunk and decides the timeout for the response if still searching
|
||||||
func (self *Depo) strategyUpdateRequest(rs *storage.RequestStatus, origReq *retrieveRequestMsgData) (req *retrieveRequestMsgData) {
|
func (d *Depo) strategyUpdateRequest(rs *storage.RequestStatus, origReq *retrieveRequestMsgData) (req *retrieveRequestMsgData) {
|
||||||
log.Trace(fmt.Sprintf("Depo.strategyUpdateRequest: key %v", origReq.Key.Log()))
|
log.Trace(fmt.Sprintf("Depo.strategyUpdateRequest: key %v", origReq.Key.Log()))
|
||||||
// we do not create an alternative one
|
// we do not create an alternative one
|
||||||
req = origReq
|
req = origReq
|
||||||
if rs != nil {
|
if rs != nil {
|
||||||
self.addRequester(rs, req)
|
d.addRequester(rs, req)
|
||||||
req.setTimeout(self.searchTimeout(rs, req))
|
req.setTimeout(d.searchTimeout(rs, req))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// decides the timeout promise sent with the immediate peers response to a retrieve request
|
// decides the timeout promise sent with the immediate peers response to a retrieve request
|
||||||
// if timeout is explicitly set and expired
|
// if timeout is explicitly set and expired
|
||||||
func (self *Depo) searchTimeout(rs *storage.RequestStatus, req *retrieveRequestMsgData) (timeout *time.Time) {
|
func (d *Depo) searchTimeout(rs *storage.RequestStatus, req *retrieveRequestMsgData) (timeout *time.Time) {
|
||||||
reqt := req.getTimeout()
|
reqt := req.getTimeout()
|
||||||
t := time.Now().Add(searchTimeout)
|
t := time.Now().Add(searchTimeout)
|
||||||
if reqt != nil && reqt.Before(t) {
|
if reqt != nil && reqt.Before(t) {
|
||||||
|
|
@ -225,7 +225,7 @@ adds a new peer to an existing open request
|
||||||
only add if less than requesterCount peers forwarded the same request id so far
|
only add if less than requesterCount peers forwarded the same request id so far
|
||||||
note this is done irrespective of status (searching or found)
|
note this is done irrespective of status (searching or found)
|
||||||
*/
|
*/
|
||||||
func (self *Depo) addRequester(rs *storage.RequestStatus, req *retrieveRequestMsgData) {
|
func (d *Depo) addRequester(rs *storage.RequestStatus, req *retrieveRequestMsgData) {
|
||||||
log.Trace(fmt.Sprintf("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.Id))
|
log.Trace(fmt.Sprintf("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.Id))
|
||||||
list := rs.Requesters[req.Id]
|
list := rs.Requesters[req.Id]
|
||||||
rs.Requesters[req.Id] = append(list, req)
|
rs.Requesters[req.Id] = append(list, req)
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ var searchTimeout = 3 * time.Second
|
||||||
|
|
||||||
// forwarding logic
|
// forwarding logic
|
||||||
// logic propagating retrieve requests to peers given by the kademlia hive
|
// logic propagating retrieve requests to peers given by the kademlia hive
|
||||||
func (self *forwarder) Retrieve(chunk *storage.Chunk) {
|
func (f *forwarder) Retrieve(chunk *storage.Chunk) {
|
||||||
peers := self.hive.getPeers(chunk.Key, 0)
|
peers := f.hive.getPeers(chunk.Key, 0)
|
||||||
log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers)))
|
log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers)))
|
||||||
OUT:
|
OUT:
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
|
|
@ -87,7 +87,7 @@ OUT:
|
||||||
// requests to specific peers given by the kademlia hive
|
// requests to specific peers given by the kademlia hive
|
||||||
// except for peers that the store request came from (if any)
|
// except for peers that the store request came from (if any)
|
||||||
// delivery queueing taken care of by syncer
|
// delivery queueing taken care of by syncer
|
||||||
func (self *forwarder) Store(chunk *storage.Chunk) {
|
func (f *forwarder) Store(chunk *storage.Chunk) {
|
||||||
var n int
|
var n int
|
||||||
msg := &storeRequestMsgData{
|
msg := &storeRequestMsgData{
|
||||||
Key: chunk.Key,
|
Key: chunk.Key,
|
||||||
|
|
@ -97,7 +97,7 @@ func (self *forwarder) Store(chunk *storage.Chunk) {
|
||||||
if chunk.Source != nil {
|
if chunk.Source != nil {
|
||||||
source = chunk.Source.(*peer)
|
source = chunk.Source.(*peer)
|
||||||
}
|
}
|
||||||
for _, p := range self.hive.getPeers(chunk.Key, 0) {
|
for _, p := range f.hive.getPeers(chunk.Key, 0) {
|
||||||
log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk))
|
log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk))
|
||||||
|
|
||||||
if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) {
|
if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) {
|
||||||
|
|
@ -109,7 +109,7 @@ func (self *forwarder) Store(chunk *storage.Chunk) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// once a chunk is found deliver it to its requesters unless timed out
|
// once a chunk is found deliver it to its requesters unless timed out
|
||||||
func (self *forwarder) Deliver(chunk *storage.Chunk) {
|
func (f *forwarder) Deliver(chunk *storage.Chunk) {
|
||||||
// iterate over request entries
|
// iterate over request entries
|
||||||
for id, requesters := range chunk.Req.Requesters {
|
for id, requesters := range chunk.Req.Requesters {
|
||||||
counter := requesterCount
|
counter := requesterCount
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ func NewDefaultHiveParams() *HiveParams {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *HiveParams) Init(path string) {
|
func (hp *HiveParams) Init(path string) {
|
||||||
self.KadDbPath = filepath.Join(path, "bzz-peers.json")
|
hp.KadDbPath = filepath.Join(path, "bzz-peers.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool) *Hive {
|
func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool) *Hive {
|
||||||
|
|
@ -108,53 +108,53 @@ func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) SyncEnabled(on bool) {
|
func (hive *Hive) SyncEnabled(on bool) {
|
||||||
self.syncEnabled = on
|
hive.syncEnabled = on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) SwapEnabled(on bool) {
|
func (hive *Hive) SwapEnabled(on bool) {
|
||||||
self.swapEnabled = on
|
hive.swapEnabled = on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) BlockNetworkRead(on bool) {
|
func (hive *Hive) BlockNetworkRead(on bool) {
|
||||||
self.blockRead = on
|
hive.blockRead = on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) BlockNetworkWrite(on bool) {
|
func (hive *Hive) BlockNetworkWrite(on bool) {
|
||||||
self.blockWrite = on
|
hive.blockWrite = on
|
||||||
}
|
}
|
||||||
|
|
||||||
// public accessor to the hive base address
|
// public accessor to the hive base address
|
||||||
func (self *Hive) Addr() kademlia.Address {
|
func (hive *Hive) Addr() kademlia.Address {
|
||||||
return self.addr
|
return hive.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start receives network info only at startup
|
// Start receives network info only at startup
|
||||||
// listedAddr is a function to retrieve listening address to advertise to peers
|
// listedAddr is a function to retrieve listening address to advertise to peers
|
||||||
// connectPeer is a function to connect to a peer based on its NodeID or enode URL
|
// connectPeer is a function to connect to a peer based on its NodeID or enode URL
|
||||||
// there are called on the p2p.Server which runs on the node
|
// there are called on the p2p.Server which runs on the node
|
||||||
func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPeer func(string) error) (err error) {
|
func (hive *Hive) Start(id discover.NodeID, listenAddr func() string, connectPeer func(string) error) (err error) {
|
||||||
self.toggle = make(chan bool)
|
hive.toggle = make(chan bool)
|
||||||
self.more = make(chan bool)
|
hive.more = make(chan bool)
|
||||||
self.quit = make(chan bool)
|
hive.quit = make(chan bool)
|
||||||
self.id = id
|
hive.id = id
|
||||||
self.listenAddr = listenAddr
|
hive.listenAddr = listenAddr
|
||||||
err = self.kad.Load(self.path, nil)
|
err = hive.kad.Load(hive.path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", self.path, err))
|
log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", hive.path, err))
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
// this loop is doing bootstrapping and maintains a healthy table
|
// this loop is doing bootstrapping and maintains a healthy table
|
||||||
go self.keepAlive()
|
go hive.keepAlive()
|
||||||
go func() {
|
go func() {
|
||||||
// whenever toggled ask kademlia about most preferred peer
|
// whenever toggled ask kademlia about most preferred peer
|
||||||
for alive := range self.more {
|
for alive := range hive.more {
|
||||||
if !alive {
|
if !alive {
|
||||||
// receiving false closes the loop while allowing parallel routines
|
// receiving false closes the loop while allowing parallel routines
|
||||||
// to attempt to write to more (remove Peer when shutting down)
|
// to attempt to write to more (remove Peer when shutting down)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node, need, proxLimit := self.kad.Suggest()
|
node, need, proxLimit := hive.kad.Suggest()
|
||||||
|
|
||||||
if node != nil && len(node.Url) > 0 {
|
if node != nil && len(node.Url) > 0 {
|
||||||
log.Trace(fmt.Sprintf("call known bee %v", node.Url))
|
log.Trace(fmt.Sprintf("call known bee %v", node.Url))
|
||||||
|
|
@ -164,10 +164,10 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
||||||
}
|
}
|
||||||
if need {
|
if need {
|
||||||
// a random peer is taken from the table
|
// a random peer is taken from the table
|
||||||
peers := self.kad.FindClosest(kademlia.RandomAddressAt(self.addr, rand.Intn(self.kad.MaxProx)), 1)
|
peers := hive.kad.FindClosest(kademlia.RandomAddressAt(hive.addr, rand.Intn(hive.kad.MaxProx)), 1)
|
||||||
if len(peers) > 0 {
|
if len(peers) > 0 {
|
||||||
// a random address at prox bin 0 is sent for lookup
|
// a random address at prox bin 0 is sent for lookup
|
||||||
randAddr := kademlia.RandomAddressAt(self.addr, proxLimit)
|
randAddr := kademlia.RandomAddressAt(hive.addr, proxLimit)
|
||||||
req := &retrieveRequestMsgData{
|
req := &retrieveRequestMsgData{
|
||||||
Key: storage.Key(randAddr[:]),
|
Key: storage.Key(randAddr[:]),
|
||||||
}
|
}
|
||||||
|
|
@ -181,11 +181,11 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
||||||
log.Info(fmt.Sprintf("no need for more bees"))
|
log.Info(fmt.Sprintf("no need for more bees"))
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case self.toggle <- need:
|
case hive.toggle <- need:
|
||||||
case <-self.quit:
|
case <-hive.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", self.addr, self.kad.Count(), self.kad.DBCount()))
|
log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", hive.addr, hive.kad.Count(), hive.kad.DBCount()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
|
|
@ -193,60 +193,60 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
||||||
|
|
||||||
// keepAlive is a forever loop
|
// keepAlive is a forever loop
|
||||||
// in its awake state it periodically triggers connection attempts
|
// in its awake state it periodically triggers connection attempts
|
||||||
// by writing to self.more until Kademlia Table is saturated
|
// by writing to hive.more until Kademlia Table is saturated
|
||||||
// wake state is toggled by writing to self.toggle
|
// wake state is toggled by writing to hive.toggle
|
||||||
// it restarts if the table becomes non-full again due to disconnections
|
// it restarts if the table becomes non-full again due to disconnections
|
||||||
func (self *Hive) keepAlive() {
|
func (hive *Hive) keepAlive() {
|
||||||
alarm := time.NewTicker(time.Duration(self.callInterval)).C
|
alarm := time.NewTicker(time.Duration(hive.callInterval)).C
|
||||||
for {
|
for {
|
||||||
peersNumGauge.Update(int64(self.kad.Count()))
|
peersNumGauge.Update(int64(hive.kad.Count()))
|
||||||
select {
|
select {
|
||||||
case <-alarm:
|
case <-alarm:
|
||||||
if self.kad.DBCount() > 0 {
|
if hive.kad.DBCount() > 0 {
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case hive.more <- true:
|
||||||
log.Debug(fmt.Sprintf("buzz wakeup"))
|
log.Debug(fmt.Sprintf("buzz wakeup"))
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case need := <-self.toggle:
|
case need := <-hive.toggle:
|
||||||
if alarm == nil && need {
|
if alarm == nil && need {
|
||||||
alarm = time.NewTicker(time.Duration(self.callInterval)).C
|
alarm = time.NewTicker(time.Duration(hive.callInterval)).C
|
||||||
}
|
}
|
||||||
if alarm != nil && !need {
|
if alarm != nil && !need {
|
||||||
alarm = nil
|
alarm = nil
|
||||||
|
|
||||||
}
|
}
|
||||||
case <-self.quit:
|
case <-hive.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) Stop() error {
|
func (hive *Hive) Stop() error {
|
||||||
// closing toggle channel quits the updateloop
|
// closing toggle channel quits the updateloop
|
||||||
close(self.quit)
|
close(hive.quit)
|
||||||
return self.kad.Save(self.path, saveSync)
|
return hive.kad.Save(hive.path, saveSync)
|
||||||
}
|
}
|
||||||
|
|
||||||
// called at the end of a successful protocol handshake
|
// called at the end of a successful protocol handshake
|
||||||
func (self *Hive) addPeer(p *peer) error {
|
func (hive *Hive) addPeer(p *peer) error {
|
||||||
addPeerCounter.Inc(1)
|
addPeerCounter.Inc(1)
|
||||||
defer func() {
|
defer func() {
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case hive.more <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
log.Trace(fmt.Sprintf("hi new bee %v", p))
|
log.Trace(fmt.Sprintf("hi new bee %v", p))
|
||||||
err := self.kad.On(p, loadSync)
|
err := hive.kad.On(p, loadSync)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// self lookup (can be encoded as nil/zero key since peers addr known) + no id ()
|
// hive lookup (can be encoded as nil/zero key since peers addr known) + no id ()
|
||||||
// the most common way of saying hi in bzz is initiation of gossip
|
// the most common way of saying hi in bzz is initiation of gossip
|
||||||
// let me know about anyone new from my hood , here is the storageradius
|
// let me know about anyone new from my hood , here is the storageradius
|
||||||
// to send the 6 byte self lookup
|
// to send the 6 byte hive lookup
|
||||||
// we do not record as request or forward it, just reply with peers
|
// we do not record as request or forward it, just reply with peers
|
||||||
p.retrieve(&retrieveRequestMsgData{})
|
p.retrieve(&retrieveRequestMsgData{})
|
||||||
log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p))
|
log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p))
|
||||||
|
|
@ -255,33 +255,33 @@ func (self *Hive) addPeer(p *peer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called after peer disconnected
|
// called after peer disconnected
|
||||||
func (self *Hive) removePeer(p *peer) {
|
func (hive *Hive) removePeer(p *peer) {
|
||||||
removePeerCounter.Inc(1)
|
removePeerCounter.Inc(1)
|
||||||
log.Debug(fmt.Sprintf("bee %v removed", p))
|
log.Debug(fmt.Sprintf("bee %v removed", p))
|
||||||
self.kad.Off(p, saveSync)
|
hive.kad.Off(p, saveSync)
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case hive.more <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
if self.kad.Count() == 0 {
|
if hive.kad.Count() == 0 {
|
||||||
log.Debug(fmt.Sprintf("empty, all bees gone"))
|
log.Debug(fmt.Sprintf("empty, all bees gone"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a list of live peers that are closer to target than us
|
// Retrieve a list of live peers that are closer to target than us
|
||||||
func (self *Hive) getPeers(target storage.Key, max int) (peers []*peer) {
|
func (hive *Hive) getPeers(target storage.Key, max int) (peers []*peer) {
|
||||||
var addr kademlia.Address
|
var addr kademlia.Address
|
||||||
copy(addr[:], target[:])
|
copy(addr[:], target[:])
|
||||||
for _, node := range self.kad.FindClosest(addr, max) {
|
for _, node := range hive.kad.FindClosest(addr, max) {
|
||||||
peers = append(peers, node.(*peer))
|
peers = append(peers, node.(*peer))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// disconnects all the peers
|
// disconnects all the peers
|
||||||
func (self *Hive) DropAll() {
|
func (hive *Hive) DropAll() {
|
||||||
log.Info(fmt.Sprintf("dropping all bees"))
|
log.Info(fmt.Sprintf("dropping all bees"))
|
||||||
for _, node := range self.kad.FindClosest(kademlia.Address{}, 0) {
|
for _, node := range hive.kad.FindClosest(kademlia.Address{}, 0) {
|
||||||
node.Drop()
|
node.Drop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +301,7 @@ func newNodeRecord(addr *peerAddr) *kademlia.NodeRecord {
|
||||||
// called by the protocol when receiving peerset (for target address)
|
// called by the protocol when receiving peerset (for target address)
|
||||||
// peersMsgData is converted to a slice of NodeRecords for Kademlia
|
// peersMsgData is converted to a slice of NodeRecords for Kademlia
|
||||||
// this is to store all thats needed
|
// this is to store all thats needed
|
||||||
func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
|
func (hive *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
|
||||||
var nrs []*kademlia.NodeRecord
|
var nrs []*kademlia.NodeRecord
|
||||||
for _, p := range req.Peers {
|
for _, p := range req.Peers {
|
||||||
if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil {
|
if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil {
|
||||||
|
|
@ -310,7 +310,7 @@ func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
|
||||||
}
|
}
|
||||||
nrs = append(nrs, newNodeRecord(p))
|
nrs = append(nrs, newNodeRecord(p))
|
||||||
}
|
}
|
||||||
self.kad.Add(nrs)
|
hive.kad.Add(nrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// peer wraps the protocol instance to represent a connected peer
|
// peer wraps the protocol instance to represent a connected peer
|
||||||
|
|
@ -320,17 +320,17 @@ type peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// protocol instance implements kademlia.Node interface (embedded peer)
|
// protocol instance implements kademlia.Node interface (embedded peer)
|
||||||
func (self *peer) Addr() kademlia.Address {
|
func (p *peer) Addr() kademlia.Address {
|
||||||
return self.remoteAddr.Addr
|
return p.remoteAddr.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peer) Url() string {
|
func (p *peer) Url() string {
|
||||||
return self.remoteAddr.String()
|
return p.remoteAddr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO take into account traffic
|
// TODO take into account traffic
|
||||||
func (self *peer) LastActive() time.Time {
|
func (p *peer) LastActive() time.Time {
|
||||||
return self.lastActive
|
return p.lastActive
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads the serialised form of sync state persisted as the 'Meta' attribute
|
// reads the serialised form of sync state persisted as the 'Meta' attribute
|
||||||
|
|
@ -370,19 +370,19 @@ func saveSync(record *kademlia.NodeRecord, node kademlia.Node) {
|
||||||
// the immediate response to a retrieve request,
|
// the immediate response to a retrieve request,
|
||||||
// sends relevant peer data given by the kademlia hive to the requester
|
// sends relevant peer data given by the kademlia hive to the requester
|
||||||
// TODO: remember peers sent for duration of the session, only new peers sent
|
// TODO: remember peers sent for duration of the session, only new peers sent
|
||||||
func (self *Hive) peers(req *retrieveRequestMsgData) {
|
func (hive *Hive) peers(req *retrieveRequestMsgData) {
|
||||||
if req != nil {
|
if req != nil {
|
||||||
var addrs []*peerAddr
|
var addrs []*peerAddr
|
||||||
if req.timeout == nil || time.Now().Before(*(req.timeout)) {
|
if req.timeout == nil || time.Now().Before(*(req.timeout)) {
|
||||||
key := req.Key
|
key := req.Key
|
||||||
// self lookup from remote peer
|
// hive lookup from remote peer
|
||||||
if storage.IsZeroKey(key) {
|
if storage.IsZeroKey(key) {
|
||||||
addr := req.from.Addr()
|
addr := req.from.Addr()
|
||||||
key = storage.Key(addr[:])
|
key = storage.Key(addr[:])
|
||||||
req.Key = nil
|
req.Key = nil
|
||||||
}
|
}
|
||||||
// get peer addresses from hive
|
// get peer addresses from hive
|
||||||
for _, peer := range self.getPeers(key, int(req.MaxPeers)) {
|
for _, peer := range hive.getPeers(key, int(req.MaxPeers)) {
|
||||||
addrs = append(addrs, peer.remoteAddr)
|
addrs = append(addrs, peer.remoteAddr)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log()))
|
log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log()))
|
||||||
|
|
@ -398,6 +398,6 @@ func (self *Hive) peers(req *retrieveRequestMsgData) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) String() string {
|
func (hive *Hive) String() string {
|
||||||
return self.kad.String()
|
return hive.kad.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,14 @@ type NodeRecord struct {
|
||||||
node Node
|
node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NodeRecord) setSeen() {
|
func (record *NodeRecord) setSeen() {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
self.Seen = t
|
record.Seen = t
|
||||||
self.After = t
|
record.After = t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NodeRecord) String() string {
|
func (record *NodeRecord) String() string {
|
||||||
return fmt.Sprintf("<%v>", self.Addr)
|
return fmt.Sprintf("<%v>", record.Addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// persisted node record database ()
|
// persisted node record database ()
|
||||||
|
|
@ -77,11 +77,11 @@ func newKadDb(addr Address, params *KadParams) *KadDb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
func (db *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
|
|
||||||
record, found := self.index[a]
|
record, found := db.index[a]
|
||||||
if !found {
|
if !found {
|
||||||
record = &NodeRecord{
|
record = &NodeRecord{
|
||||||
Addr: a,
|
Addr: a,
|
||||||
|
|
@ -89,8 +89,8 @@ func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("add new record %v to kaddb", record))
|
log.Info(fmt.Sprintf("add new record %v to kaddb", record))
|
||||||
// insert in kaddb
|
// insert in kaddb
|
||||||
self.index[a] = record
|
db.index[a] = record
|
||||||
self.Nodes[index] = append(self.Nodes[index], record)
|
db.Nodes[index] = append(db.Nodes[index], record)
|
||||||
} else {
|
} else {
|
||||||
log.Info(fmt.Sprintf("found record %v in kaddb", record))
|
log.Info(fmt.Sprintf("found record %v in kaddb", record))
|
||||||
}
|
}
|
||||||
|
|
@ -102,26 +102,26 @@ func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add adds node records to kaddb (persisted node record db)
|
// add adds node records to kaddb (persisted node record db)
|
||||||
func (self *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) {
|
func (db *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) {
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
var n int
|
var n int
|
||||||
var nodes []*NodeRecord
|
var nodes []*NodeRecord
|
||||||
for _, node := range nrs {
|
for _, node := range nrs {
|
||||||
_, found := self.index[node.Addr]
|
_, found := db.index[node.Addr]
|
||||||
if !found && node.Addr != self.Address {
|
if !found && node.Addr != db.Address {
|
||||||
node.setSeen()
|
node.setSeen()
|
||||||
self.index[node.Addr] = node
|
db.index[node.Addr] = node
|
||||||
index := proximityBin(node.Addr)
|
index := proximityBin(node.Addr)
|
||||||
dbcursor := self.cursors[index]
|
dbcursor := db.cursors[index]
|
||||||
nodes = self.Nodes[index]
|
nodes = db.Nodes[index]
|
||||||
// this is inefficient for allocation, need to just append then shift
|
// this is inefficient for allocation, need to just append then shift
|
||||||
newnodes := make([]*NodeRecord, len(nodes)+1)
|
newnodes := make([]*NodeRecord, len(nodes)+1)
|
||||||
copy(newnodes[:], nodes[:dbcursor])
|
copy(newnodes[:], nodes[:dbcursor])
|
||||||
newnodes[dbcursor] = node
|
newnodes[dbcursor] = node
|
||||||
copy(newnodes[dbcursor+1:], nodes[dbcursor:])
|
copy(newnodes[dbcursor+1:], nodes[dbcursor:])
|
||||||
log.Trace(fmt.Sprintf("new nodes: %v, nodes: %v", newnodes, nodes))
|
log.Trace(fmt.Sprintf("new nodes: %v, nodes: %v", newnodes, nodes))
|
||||||
self.Nodes[index] = newnodes
|
db.Nodes[index] = newnodes
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,10 +168,10 @@ offline past peer)
|
||||||
|
|
||||||
The second argument returned names the first missing slot found
|
The second argument returned names the first missing slot found
|
||||||
*/
|
*/
|
||||||
func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRecord, need bool, proxLimit int) {
|
func (db *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRecord, need bool, proxLimit int) {
|
||||||
// return nil, proxLimit indicates that all buckets are filled
|
// return nil, proxLimit indicates that all buckets are filled
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
|
|
||||||
var interval time.Duration
|
var interval time.Duration
|
||||||
var found bool
|
var found bool
|
||||||
|
|
@ -185,7 +185,7 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
for rounds := 1; rounds <= maxBinSize; rounds++ {
|
for rounds := 1; rounds <= maxBinSize; rounds++ {
|
||||||
ROUND:
|
ROUND:
|
||||||
// iterate over rows from PO 0 upto MaxProx
|
// iterate over rows from PO 0 upto MaxProx
|
||||||
for po, dbrow := range self.Nodes {
|
for po, dbrow := range db.Nodes {
|
||||||
// if row has rounds connected peers, then take the next
|
// if row has rounds connected peers, then take the next
|
||||||
if binSize(po) >= rounds {
|
if binSize(po) >= rounds {
|
||||||
continue ROUND
|
continue ROUND
|
||||||
|
|
@ -200,7 +200,7 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
// there is a missing slot - finding a node to connect to
|
// there is a missing slot - finding a node to connect to
|
||||||
// select a node record from the relavant kaddb row (of identical prox order)
|
// select a node record from the relavant kaddb row (of identical prox order)
|
||||||
ROW:
|
ROW:
|
||||||
for cursor = self.cursors[po]; !found && count < len(dbrow); cursor = (cursor + 1) % len(dbrow) {
|
for cursor = db.cursors[po]; !found && count < len(dbrow); cursor = (cursor + 1) % len(dbrow) {
|
||||||
count++
|
count++
|
||||||
node = dbrow[cursor]
|
node = dbrow[cursor]
|
||||||
|
|
||||||
|
|
@ -217,10 +217,10 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = time.Since(node.Seen)
|
delta = time.Since(node.Seen)
|
||||||
if delta < self.initialRetryInterval {
|
if delta < db.initialRetryInterval {
|
||||||
delta = self.initialRetryInterval
|
delta = db.initialRetryInterval
|
||||||
}
|
}
|
||||||
if delta > self.purgeInterval {
|
if delta > db.purgeInterval {
|
||||||
// remove node
|
// remove node
|
||||||
purge[cursor] = true
|
purge[cursor] = true
|
||||||
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen))
|
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen))
|
||||||
|
|
@ -230,15 +230,15 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After))
|
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After))
|
||||||
|
|
||||||
// scheduling next check
|
// scheduling next check
|
||||||
interval = delta * time.Duration(self.connRetryExp)
|
interval = delta * time.Duration(db.connRetryExp)
|
||||||
after = time.Now().Add(interval)
|
after = time.Now().Add(interval)
|
||||||
|
|
||||||
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval))
|
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval))
|
||||||
node.After = after
|
node.After = after
|
||||||
found = true
|
found = true
|
||||||
} // ROW
|
} // ROW
|
||||||
self.cursors[po] = cursor
|
db.cursors[po] = cursor
|
||||||
self.delete(po, purge)
|
db.delete(po, purge)
|
||||||
if found {
|
if found {
|
||||||
return node, need, proxLimit
|
return node, need, proxLimit
|
||||||
}
|
}
|
||||||
|
|
@ -251,33 +251,33 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
// deletes the noderecords of a kaddb row corresponding to the indexes
|
// deletes the noderecords of a kaddb row corresponding to the indexes
|
||||||
// caller must hold the dblock
|
// caller must hold the dblock
|
||||||
// the call is unsafe, no index checks
|
// the call is unsafe, no index checks
|
||||||
func (self *KadDb) delete(row int, purge []bool) {
|
func (db *KadDb) delete(row int, purge []bool) {
|
||||||
var nodes []*NodeRecord
|
var nodes []*NodeRecord
|
||||||
dbrow := self.Nodes[row]
|
dbrow := db.Nodes[row]
|
||||||
for i, del := range purge {
|
for i, del := range purge {
|
||||||
if i == self.cursors[row] {
|
if i == db.cursors[row] {
|
||||||
//reset cursor
|
//reset cursor
|
||||||
self.cursors[row] = len(nodes)
|
db.cursors[row] = len(nodes)
|
||||||
}
|
}
|
||||||
// delete the entry to be purged
|
// delete the entry to be purged
|
||||||
if del {
|
if del {
|
||||||
delete(self.index, dbrow[i].Addr)
|
delete(db.index, dbrow[i].Addr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// otherwise append to new list
|
// otherwise append to new list
|
||||||
nodes = append(nodes, dbrow[i])
|
nodes = append(nodes, dbrow[i])
|
||||||
}
|
}
|
||||||
self.Nodes[row] = nodes
|
db.Nodes[row] = nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
// save persists kaddb on disk (written to file on path in json format.
|
// save persists kaddb on disk (written to file on path in json format.
|
||||||
func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
func (db *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
|
|
||||||
var n int
|
var n int
|
||||||
|
|
||||||
for _, b := range self.Nodes {
|
for _, b := range db.Nodes {
|
||||||
for _, node := range b {
|
for _, node := range b {
|
||||||
n++
|
n++
|
||||||
node.After = time.Now()
|
node.After = time.Now()
|
||||||
|
|
@ -288,7 +288,7 @@ func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.MarshalIndent(self, "", " ")
|
data, err := json.MarshalIndent(db, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -302,9 +302,9 @@ func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load(path) loads the node record database (kaddb) from file on path.
|
// Load(path) loads the node record database (kaddb) from file on path.
|
||||||
func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
func (db *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
|
|
||||||
var data []byte
|
var data []byte
|
||||||
data, err = ioutil.ReadFile(path)
|
data, err = ioutil.ReadFile(path)
|
||||||
|
|
@ -312,13 +312,13 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(data, self)
|
err = json.Unmarshal(data, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var n int
|
var n int
|
||||||
var purge []bool
|
var purge []bool
|
||||||
for po, b := range self.Nodes {
|
for po, b := range db.Nodes {
|
||||||
purge = make([]bool, len(b))
|
purge = make([]bool, len(b))
|
||||||
ROW:
|
ROW:
|
||||||
for i, node := range b {
|
for i, node := range b {
|
||||||
|
|
@ -333,9 +333,9 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
|
||||||
if node.After.IsZero() {
|
if node.After.IsZero() {
|
||||||
node.After = time.Now()
|
node.After = time.Now()
|
||||||
}
|
}
|
||||||
self.index[node.Addr] = node
|
db.index[node.Addr] = node
|
||||||
}
|
}
|
||||||
self.delete(po, purge)
|
db.delete(po, purge)
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("loaded kaddb with %v nodes from %v", n, path))
|
log.Info(fmt.Sprintf("loaded kaddb with %v nodes from %v", n, path))
|
||||||
|
|
||||||
|
|
@ -343,8 +343,8 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD offline db count
|
// accessor for KAD offline db count
|
||||||
func (self *KadDb) count() int {
|
func (db *KadDb) count() int {
|
||||||
defer self.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
self.lock.Lock()
|
db.lock.Lock()
|
||||||
return len(self.index)
|
return len(db.index)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,31 +109,31 @@ func New(addr Address, params *KadParams) *Kademlia {
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD base address
|
// accessor for KAD base address
|
||||||
func (self *Kademlia) Addr() Address {
|
func (kad *Kademlia) Addr() Address {
|
||||||
return self.addr
|
return kad.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD active node count
|
// accessor for KAD active node count
|
||||||
func (self *Kademlia) Count() int {
|
func (kad *Kademlia) Count() int {
|
||||||
defer self.lock.Unlock()
|
defer kad.lock.Unlock()
|
||||||
self.lock.Lock()
|
kad.lock.Lock()
|
||||||
return self.count
|
return kad.count
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD active node count
|
// accessor for KAD active node count
|
||||||
func (self *Kademlia) DBCount() int {
|
func (kad *Kademlia) DBCount() int {
|
||||||
return self.db.count()
|
return kad.db.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
// On is the entry point called when a new nodes is added
|
// On is the entry point called when a new nodes is added
|
||||||
// unsafe in that node is not checked to be already active node (to be called once)
|
// unsafe in that node is not checked to be already active node (to be called once)
|
||||||
func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) {
|
func (kad *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) {
|
||||||
log.Debug(fmt.Sprintf("%v", self))
|
log.Debug(fmt.Sprintf("%v", kad))
|
||||||
defer self.lock.Unlock()
|
defer kad.lock.Unlock()
|
||||||
self.lock.Lock()
|
kad.lock.Lock()
|
||||||
|
|
||||||
index := self.proximityBin(node.Addr())
|
index := kad.proximityBin(node.Addr())
|
||||||
record := self.db.findOrCreate(index, node.Addr(), node.Url())
|
record := kad.db.findOrCreate(index, node.Addr(), node.Url())
|
||||||
|
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
err = cb(record, node)
|
err = cb(record, node)
|
||||||
|
|
@ -145,21 +145,21 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert in kademlia table of active nodes
|
// insert in kademlia table of active nodes
|
||||||
bucket := self.buckets[index]
|
bucket := kad.buckets[index]
|
||||||
// if bucket is full insertion replaces the worst node
|
// if bucket is full insertion replaces the worst node
|
||||||
// TODO: give priority to peers with active traffic
|
// TODO: give priority to peers with active traffic
|
||||||
if len(bucket) < self.BucketSize { // >= allows us to add peers beyond the bucketsize limitation
|
if len(bucket) < kad.BucketSize { // >= allows us to add peers beyond the bucketsize limitation
|
||||||
self.buckets[index] = append(bucket, node)
|
kad.buckets[index] = append(bucket, node)
|
||||||
bucketAddIndexCount[index].Inc(1)
|
bucketAddIndexCount[index].Inc(1)
|
||||||
log.Debug(fmt.Sprintf("add node %v to table", node))
|
log.Debug(fmt.Sprintf("add node %v to table", node))
|
||||||
self.setProxLimit(index, true)
|
kad.setProxLimit(index, true)
|
||||||
record.node = node
|
record.node = node
|
||||||
self.count++
|
kad.count++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// always rotate peers
|
// always rotate peers
|
||||||
idle := self.MaxIdleInterval
|
idle := kad.MaxIdleInterval
|
||||||
var pos int
|
var pos int
|
||||||
var replaced Node
|
var replaced Node
|
||||||
for i, p := range bucket {
|
for i, p := range bucket {
|
||||||
|
|
@ -174,41 +174,41 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
|
||||||
log.Debug(fmt.Sprintf("all peers wanted, PO%03d bucket full", index))
|
log.Debug(fmt.Sprintf("all peers wanted, PO%03d bucket full", index))
|
||||||
return fmt.Errorf("bucket full")
|
return fmt.Errorf("bucket full")
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("node %v replaced by %v (idle for %v > %v)", replaced, node, idle, self.MaxIdleInterval))
|
log.Debug(fmt.Sprintf("node %v replaced by %v (idle for %v > %v)", replaced, node, idle, kad.MaxIdleInterval))
|
||||||
replaced.Drop()
|
replaced.Drop()
|
||||||
// actually replace in the row. When off(node) is called, the peer is no longer in the row
|
// actually replace in the row. When off(node) is called, the peer is no longer in the row
|
||||||
bucket[pos] = node
|
bucket[pos] = node
|
||||||
// there is no change in bucket cardinalities so no prox limit adjustment is needed
|
// there is no change in bucket cardinalities so no prox limit adjustment is needed
|
||||||
record.node = node
|
record.node = node
|
||||||
self.count++
|
kad.count++
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off is the called when a node is taken offline (from the protocol main loop exit)
|
// Off is the called when a node is taken offline (from the protocol main loop exit)
|
||||||
func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
func (kad *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
||||||
self.lock.Lock()
|
kad.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer kad.lock.Unlock()
|
||||||
|
|
||||||
index := self.proximityBin(node.Addr())
|
index := kad.proximityBin(node.Addr())
|
||||||
bucketRmIndexCount[index].Inc(1)
|
bucketRmIndexCount[index].Inc(1)
|
||||||
bucket := self.buckets[index]
|
bucket := kad.buckets[index]
|
||||||
for i := 0; i < len(bucket); i++ {
|
for i := 0; i < len(bucket); i++ {
|
||||||
if node.Addr() == bucket[i].Addr() {
|
if node.Addr() == bucket[i].Addr() {
|
||||||
self.buckets[index] = append(bucket[:i], bucket[(i+1):]...)
|
kad.buckets[index] = append(bucket[:i], bucket[(i+1):]...)
|
||||||
self.setProxLimit(index, false)
|
kad.setProxLimit(index, false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record := self.db.index[node.Addr()]
|
record := kad.db.index[node.Addr()]
|
||||||
// callback on remove
|
// callback on remove
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
cb(record, record.node)
|
cb(record, record.node)
|
||||||
}
|
}
|
||||||
record.node = nil
|
record.node = nil
|
||||||
self.count--
|
kad.count--
|
||||||
log.Debug(fmt.Sprintf("remove node %v from table, population now is %v", node, self.count))
|
log.Debug(fmt.Sprintf("remove node %v from table, population now is %v", node, kad.count))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -218,39 +218,39 @@ func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
||||||
// 2) the sum of all items are the minimum possible but higher than ProxBinSize
|
// 2) the sum of all items are the minimum possible but higher than ProxBinSize
|
||||||
// adjust Prox (proxLimit and proxSize after an insertion/removal of nodes)
|
// adjust Prox (proxLimit and proxSize after an insertion/removal of nodes)
|
||||||
// caller holds the lock
|
// caller holds the lock
|
||||||
func (self *Kademlia) setProxLimit(r int, on bool) {
|
func (kad *Kademlia) setProxLimit(r int, on bool) {
|
||||||
// if the change is outside the core (PO lower)
|
// if the change is outside the core (PO lower)
|
||||||
// and the change does not leave a bucket empty then
|
// and the change does not leave a bucket empty then
|
||||||
// no adjustment needed
|
// no adjustment needed
|
||||||
if r < self.proxLimit && len(self.buckets[r]) > 0 {
|
if r < kad.proxLimit && len(kad.buckets[r]) > 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// if on=a node was added, then r must be within prox limit so increment cardinality
|
// if on=a node was added, then r must be within prox limit so increment cardinality
|
||||||
if on {
|
if on {
|
||||||
self.proxSize++
|
kad.proxSize++
|
||||||
curr := len(self.buckets[self.proxLimit])
|
curr := len(kad.buckets[kad.proxLimit])
|
||||||
// if now core is big enough without the furthest bucket, then contract
|
// if now core is big enough without the furthest bucket, then contract
|
||||||
// this can result in more than one bucket change
|
// this can result in more than one bucket change
|
||||||
for self.proxSize >= self.ProxBinSize+curr && curr > 0 {
|
for kad.proxSize >= kad.ProxBinSize+curr && curr > 0 {
|
||||||
self.proxSize -= curr
|
kad.proxSize -= curr
|
||||||
self.proxLimit++
|
kad.proxLimit++
|
||||||
curr = len(self.buckets[self.proxLimit])
|
curr = len(kad.buckets[kad.proxLimit])
|
||||||
|
|
||||||
log.Trace(fmt.Sprintf("proxbin contraction (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
|
log.Trace(fmt.Sprintf("proxbin contraction (size: %v, limit: %v, bin: %v)", kad.proxSize, kad.proxLimit, r))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// otherwise
|
// otherwise
|
||||||
if r >= self.proxLimit {
|
if r >= kad.proxLimit {
|
||||||
self.proxSize--
|
kad.proxSize--
|
||||||
}
|
}
|
||||||
// expand core by lowering prox limit until hit zero or cover the empty bucket or reached target cardinality
|
// expand core by lowering prox limit until hit zero or cover the empty bucket or reached target cardinality
|
||||||
for (self.proxSize < self.ProxBinSize || r < self.proxLimit) &&
|
for (kad.proxSize < kad.ProxBinSize || r < kad.proxLimit) &&
|
||||||
self.proxLimit > 0 {
|
kad.proxLimit > 0 {
|
||||||
//
|
//
|
||||||
self.proxLimit--
|
kad.proxLimit--
|
||||||
self.proxSize += len(self.buckets[self.proxLimit])
|
kad.proxSize += len(kad.buckets[kad.proxLimit])
|
||||||
log.Trace(fmt.Sprintf("proxbin expansion (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
|
log.Trace(fmt.Sprintf("proxbin expansion (size: %v, limit: %v, bin: %v)", kad.proxSize, kad.proxLimit, r))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,15 +259,15 @@ returns the list of nodes belonging to the same proximity bin
|
||||||
as the target. The most proximate bin will be the union of the bins between
|
as the target. The most proximate bin will be the union of the bins between
|
||||||
proxLimit and MaxProx.
|
proxLimit and MaxProx.
|
||||||
*/
|
*/
|
||||||
func (self *Kademlia) FindClosest(target Address, max int) []Node {
|
func (kad *Kademlia) FindClosest(target Address, max int) []Node {
|
||||||
self.lock.Lock()
|
kad.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer kad.lock.Unlock()
|
||||||
|
|
||||||
r := nodesByDistance{
|
r := nodesByDistance{
|
||||||
target: target,
|
target: target,
|
||||||
}
|
}
|
||||||
|
|
||||||
po := self.proximityBin(target)
|
po := kad.proximityBin(target)
|
||||||
index := po
|
index := po
|
||||||
step := 1
|
step := 1
|
||||||
log.Trace(fmt.Sprintf("serving %v nodes at %v (PO%02d)", max, index, po))
|
log.Trace(fmt.Sprintf("serving %v nodes at %v (PO%02d)", max, index, po))
|
||||||
|
|
@ -284,17 +284,17 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
|
||||||
var n int
|
var n int
|
||||||
for index >= 0 {
|
for index >= 0 {
|
||||||
// add entire bucket
|
// add entire bucket
|
||||||
for _, p := range self.buckets[index] {
|
for _, p := range kad.buckets[index] {
|
||||||
r.push(p, limit)
|
r.push(p, limit)
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
// terminate if index reached the bottom or enough peers > min
|
// terminate if index reached the bottom or enough peers > min
|
||||||
log.Trace(fmt.Sprintf("add %v -> %v (PO%02d, PO%03d)", len(self.buckets[index]), n, index, po))
|
log.Trace(fmt.Sprintf("add %v -> %v (PO%02d, PO%03d)", len(kad.buckets[index]), n, index, po))
|
||||||
if n >= min && (step < 0 || max == 0) {
|
if n >= min && (step < 0 || max == 0) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// reach top most non-empty PO bucket, turn around
|
// reach top most non-empty PO bucket, turn around
|
||||||
if index == self.MaxProx {
|
if index == kad.MaxProx {
|
||||||
index = po
|
index = po
|
||||||
step = -1
|
step = -1
|
||||||
}
|
}
|
||||||
|
|
@ -304,15 +304,15 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
|
||||||
return r.nodes
|
return r.nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Kademlia) Suggest() (*NodeRecord, bool, int) {
|
func (kad *Kademlia) Suggest() (*NodeRecord, bool, int) {
|
||||||
defer self.lock.RUnlock()
|
defer kad.lock.RUnlock()
|
||||||
self.lock.RLock()
|
kad.lock.RLock()
|
||||||
return self.db.findBest(self.BucketSize, func(i int) int { return len(self.buckets[i]) })
|
return kad.db.findBest(kad.BucketSize, func(i int) int { return len(kad.buckets[i]) })
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds node records to kaddb (persisted node record db)
|
// adds node records to kaddb (persisted node record db)
|
||||||
func (self *Kademlia) Add(nrs []*NodeRecord) {
|
func (kad *Kademlia) Add(nrs []*NodeRecord) {
|
||||||
self.db.add(nrs, self.proximityBin)
|
kad.db.add(nrs, kad.proximityBin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodesByDistance is a list of nodes, ordered by distance to target.
|
// nodesByDistance is a list of nodes, ordered by distance to target.
|
||||||
|
|
@ -369,52 +369,52 @@ a guaranteed constant maximum limit on the number of hops needed to reach one
|
||||||
node from the other.
|
node from the other.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (self *Kademlia) proximityBin(other Address) (ret int) {
|
func (kad *Kademlia) proximityBin(other Address) (ret int) {
|
||||||
ret = proximity(self.addr, other)
|
ret = proximity(kad.addr, other)
|
||||||
if ret > self.MaxProx {
|
if ret > kad.MaxProx {
|
||||||
ret = self.MaxProx
|
ret = kad.MaxProx
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// provides keyrange for chunk db iteration
|
// provides keyrange for chunk db iteration
|
||||||
func (self *Kademlia) KeyRange(other Address) (start, stop Address) {
|
func (kad *Kademlia) KeyRange(other Address) (start, stop Address) {
|
||||||
defer self.lock.RUnlock()
|
defer kad.lock.RUnlock()
|
||||||
self.lock.RLock()
|
kad.lock.RLock()
|
||||||
return KeyRange(self.addr, other, self.proxLimit)
|
return KeyRange(kad.addr, other, kad.proxLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// save persists kaddb on disk (written to file on path in json format.
|
// save persists kaddb on disk (written to file on path in json format.
|
||||||
func (self *Kademlia) Save(path string, cb func(*NodeRecord, Node)) error {
|
func (kad *Kademlia) Save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
return self.db.save(path, cb)
|
return kad.db.save(path, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load(path) loads the node record database (kaddb) from file on path.
|
// Load(path) loads the node record database (kaddb) from file on path.
|
||||||
func (self *Kademlia) Load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
func (kad *Kademlia) Load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
||||||
return self.db.load(path, cb)
|
return kad.db.load(path, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// kademlia table + kaddb table displayed with ascii
|
// kademlia table + kaddb table displayed with ascii
|
||||||
func (self *Kademlia) String() string {
|
func (kad *Kademlia) String() string {
|
||||||
defer self.lock.RUnlock()
|
defer kad.lock.RUnlock()
|
||||||
self.lock.RLock()
|
kad.lock.RLock()
|
||||||
defer self.db.lock.RUnlock()
|
defer kad.db.lock.RUnlock()
|
||||||
self.db.lock.RLock()
|
kad.db.lock.RLock()
|
||||||
|
|
||||||
var rows []string
|
var rows []string
|
||||||
rows = append(rows, "=========================================================================")
|
rows = append(rows, "=========================================================================")
|
||||||
rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), self.addr.String()[:6]))
|
rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), kad.addr.String()[:6]))
|
||||||
rows = append(rows, fmt.Sprintf("population: %d (%d), proxLimit: %d, proxSize: %d", self.count, len(self.db.index), self.proxLimit, self.proxSize))
|
rows = append(rows, fmt.Sprintf("population: %d (%d), proxLimit: %d, proxSize: %d", kad.count, len(kad.db.index), kad.proxLimit, kad.proxSize))
|
||||||
rows = append(rows, fmt.Sprintf("MaxProx: %d, ProxBinSize: %d, BucketSize: %d", self.MaxProx, self.ProxBinSize, self.BucketSize))
|
rows = append(rows, fmt.Sprintf("MaxProx: %d, ProxBinSize: %d, BucketSize: %d", kad.MaxProx, kad.ProxBinSize, kad.BucketSize))
|
||||||
|
|
||||||
for i, bucket := range self.buckets {
|
for i, bucket := range kad.buckets {
|
||||||
|
|
||||||
if i == self.proxLimit {
|
if i == kad.proxLimit {
|
||||||
rows = append(rows, fmt.Sprintf("============ PROX LIMIT: %d ==========================================", i))
|
rows = append(rows, fmt.Sprintf("============ PROX LIMIT: %d ==========================================", i))
|
||||||
}
|
}
|
||||||
row := []string{fmt.Sprintf("%03d", i), fmt.Sprintf("%2d", len(bucket))}
|
row := []string{fmt.Sprintf("%03d", i), fmt.Sprintf("%2d", len(bucket))}
|
||||||
var k int
|
var k int
|
||||||
c := self.db.cursors[i]
|
c := kad.db.cursors[i]
|
||||||
for ; k < len(bucket); k++ {
|
for ; k < len(bucket); k++ {
|
||||||
p := bucket[(c+k)%len(bucket)]
|
p := bucket[(c+k)%len(bucket)]
|
||||||
row = append(row, p.Addr().String()[:6])
|
row = append(row, p.Addr().String()[:6])
|
||||||
|
|
@ -425,16 +425,16 @@ func (self *Kademlia) String() string {
|
||||||
for ; k < 4; k++ {
|
for ; k < 4; k++ {
|
||||||
row = append(row, " ")
|
row = append(row, " ")
|
||||||
}
|
}
|
||||||
row = append(row, fmt.Sprintf("| %2d %2d", len(self.db.Nodes[i]), self.db.cursors[i]))
|
row = append(row, fmt.Sprintf("| %2d %2d", len(kad.db.Nodes[i]), kad.db.cursors[i]))
|
||||||
|
|
||||||
for j, p := range self.db.Nodes[i] {
|
for j, p := range kad.db.Nodes[i] {
|
||||||
row = append(row, p.Addr.String()[:6])
|
row = append(row, p.Addr.String()[:6])
|
||||||
if j == 3 {
|
if j == 3 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows = append(rows, strings.Join(row, " "))
|
rows = append(rows, strings.Join(row, " "))
|
||||||
if i == self.MaxProx {
|
if i == kad.MaxProx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows = append(rows, "=========================================================================")
|
rows = append(rows, "=========================================================================")
|
||||||
|
|
@ -442,12 +442,12 @@ func (self *Kademlia) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
//We have to build up the array of counters for each index
|
//We have to build up the array of counters for each index
|
||||||
func (self *Kademlia) initMetricsVariables() {
|
func (kad *Kademlia) initMetricsVariables() {
|
||||||
//create the arrays
|
//create the arrays
|
||||||
bucketAddIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
bucketAddIndexCount = make([]metrics.Counter, kad.MaxProx+1)
|
||||||
bucketRmIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
bucketRmIndexCount = make([]metrics.Counter, kad.MaxProx+1)
|
||||||
//at each index create a metrics counter
|
//at each index create a metrics counter
|
||||||
for i := 0; i < (self.KadParams.MaxProx + 1); i++ {
|
for i := 0; i < (kad.KadParams.MaxProx + 1); i++ {
|
||||||
bucketAddIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.add.%d.index", i), nil)
|
bucketAddIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.add.%d.index", i), nil)
|
||||||
bucketRmIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.rm.%d.index", i), nil)
|
bucketRmIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.rm.%d.index", i), nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,31 +272,31 @@ func TestSaveLoad(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Kademlia) proxCheck(t *testing.T) bool {
|
func (kad *Kademlia) proxCheck(t *testing.T) bool {
|
||||||
var sum int
|
var sum int
|
||||||
for i, b := range self.buckets {
|
for i, b := range kad.buckets {
|
||||||
l := len(b)
|
l := len(b)
|
||||||
// if we are in the high prox multibucket
|
// if we are in the high prox multibucket
|
||||||
if i >= self.proxLimit {
|
if i >= kad.proxLimit {
|
||||||
sum += l
|
sum += l
|
||||||
} else if l == 0 {
|
} else if l == 0 {
|
||||||
t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b), self.proxLimit, self)
|
t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b), kad.proxLimit, kad)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check if merged high prox bucket does not exceed size
|
// check if merged high prox bucket does not exceed size
|
||||||
if sum > 0 {
|
if sum > 0 {
|
||||||
if sum != self.proxSize {
|
if sum != kad.proxSize {
|
||||||
t.Errorf("proxSize incorrect, expected %v, got %v", sum, self.proxSize)
|
t.Errorf("proxSize incorrect, expected %v, got %v", sum, kad.proxSize)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
last := len(self.buckets[self.proxLimit])
|
last := len(kad.buckets[kad.proxLimit])
|
||||||
if last > 0 && sum >= self.ProxBinSize+last {
|
if last > 0 && sum >= kad.ProxBinSize+last {
|
||||||
t.Errorf("proxLimit %v incorrect, redundant non-empty bucket %d added to proxBin with %v (target %v)\n%v", self.proxLimit, last, sum-last, self.ProxBinSize, self)
|
t.Errorf("proxLimit %v incorrect, redundant non-empty bucket %d added to proxBin with %v (target %v)\n%v", kad.proxLimit, last, sum-last, kad.ProxBinSize, kad)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if self.proxLimit > 0 && sum < self.ProxBinSize {
|
if kad.proxLimit > 0 && sum < kad.ProxBinSize {
|
||||||
t.Errorf("proxLimit %v incorrect. proxSize %v is less than target %v, yet there is more peers", self.proxLimit, sum, self.ProxBinSize)
|
t.Errorf("proxLimit %v incorrect. proxSize %v is less than target %v, yet there is more peers", kad.proxLimit, sum, kad.ProxBinSize)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ type statusMsgData struct {
|
||||||
NetworkId uint64
|
NetworkId uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *statusMsgData) String() string {
|
func (data *statusMsgData) String() string {
|
||||||
return fmt.Sprintf("Status: Version: %v, ID: %v, Addr: %v, Swap: %v, NetworkId: %v", self.Version, self.ID, self.Addr, self.Swap, self.NetworkId)
|
return fmt.Sprintf("Status: Version: %v, ID: %v, Addr: %v, Swap: %v, NetworkId: %v", data.Version, data.ID, data.Addr, data.Swap, data.NetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -86,18 +86,18 @@ type storeRequestMsgData struct {
|
||||||
from *peer // [not serialised] protocol registers the requester
|
from *peer // [not serialised] protocol registers the requester
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self storeRequestMsgData) String() string {
|
func (data storeRequestMsgData) String() string {
|
||||||
var from string
|
var from string
|
||||||
if self.from == nil {
|
if data.from == nil {
|
||||||
from = "self"
|
from = "data"
|
||||||
} else {
|
} else {
|
||||||
from = self.from.Addr().String()
|
from = data.from.Addr().String()
|
||||||
}
|
}
|
||||||
end := len(self.SData)
|
end := len(data.SData)
|
||||||
if len(self.SData) > 10 {
|
if len(data.SData) > 10 {
|
||||||
end = 10
|
end = 10
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("from: %v, Key: %v; ID: %v, requestTimeout: %v, storageTimeout: %v, SData %x", from, self.Key, self.Id, self.requestTimeout, self.storageTimeout, self.SData[:end])
|
return fmt.Sprintf("from: %v, Key: %v; ID: %v, requestTimeout: %v, storageTimeout: %v, SData %x", from, data.Key, data.Id, data.requestTimeout, data.storageTimeout, data.SData[:end])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -133,40 +133,40 @@ type retrieveRequestMsgData struct {
|
||||||
from *peer //
|
from *peer //
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *retrieveRequestMsgData) String() string {
|
func (data *retrieveRequestMsgData) String() string {
|
||||||
var from string
|
var from string
|
||||||
if self.from == nil {
|
if data.from == nil {
|
||||||
from = "ourselves"
|
from = "ourselves"
|
||||||
} else {
|
} else {
|
||||||
from = self.from.Addr().String()
|
from = data.from.Addr().String()
|
||||||
}
|
}
|
||||||
var target []byte
|
var target []byte
|
||||||
if len(self.Key) > 3 {
|
if len(data.Key) > 3 {
|
||||||
target = self.Key[:4]
|
target = data.Key[:4]
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("from: %v, Key: %x; ID: %v, MaxSize: %v, MaxPeers: %d", from, target, self.Id, self.MaxSize, self.MaxPeers)
|
return fmt.Sprintf("from: %v, Key: %x; ID: %v, MaxSize: %v, MaxPeers: %d", from, target, data.Id, data.MaxSize, data.MaxPeers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookups are encoded by missing request ID
|
// lookups are encoded by missing request ID
|
||||||
func (self *retrieveRequestMsgData) isLookup() bool {
|
func (data *retrieveRequestMsgData) isLookup() bool {
|
||||||
return self.Id == 0
|
return data.Id == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets timeout fields
|
// sets timeout fields
|
||||||
func (self *retrieveRequestMsgData) setTimeout(t *time.Time) {
|
func (data *retrieveRequestMsgData) setTimeout(t *time.Time) {
|
||||||
self.timeout = t
|
data.timeout = t
|
||||||
if t != nil {
|
if t != nil {
|
||||||
self.Timeout = uint64(t.UnixNano())
|
data.Timeout = uint64(t.UnixNano())
|
||||||
} else {
|
} else {
|
||||||
self.Timeout = 0
|
data.Timeout = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *retrieveRequestMsgData) getTimeout() (t *time.Time) {
|
func (data *retrieveRequestMsgData) getTimeout() (t *time.Time) {
|
||||||
if self.Timeout > 0 && self.timeout == nil {
|
if data.Timeout > 0 && data.timeout == nil {
|
||||||
timeout := time.Unix(int64(self.Timeout), 0)
|
timeout := time.Unix(int64(data.Timeout), 0)
|
||||||
t = &timeout
|
t = &timeout
|
||||||
self.timeout = t
|
data.timeout = t
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -180,10 +180,10 @@ type peerAddr struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// peerAddr pretty prints as enode
|
// peerAddr pretty prints as enode
|
||||||
func (self *peerAddr) String() string {
|
func (data *peerAddr) String() string {
|
||||||
var nodeid discover.NodeID
|
var nodeid discover.NodeID
|
||||||
copy(nodeid[:], self.ID)
|
copy(nodeid[:], data.ID)
|
||||||
return discover.NewNode(nodeid, self.IP, 0, self.Port).String()
|
return discover.NewNode(nodeid, data.IP, 0, data.Port).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -199,7 +199,7 @@ the timeout or not.
|
||||||
NodeID serves as the owner of payment contracts and signer of proofs of transfer.
|
NodeID serves as the owner of payment contracts and signer of proofs of transfer.
|
||||||
|
|
||||||
The Key is the target (if response to a retrieval request) or missing (zero value)
|
The Key is the target (if response to a retrieval request) or missing (zero value)
|
||||||
peers address (hash of NodeID) if retrieval request was a self lookup.
|
peers address (hash of NodeID) if retrieval request was a data lookup.
|
||||||
|
|
||||||
Peers message is requested by retrieval requests with a missing or zero value request ID
|
Peers message is requested by retrieval requests with a missing or zero value request ID
|
||||||
*/
|
*/
|
||||||
|
|
@ -213,26 +213,26 @@ type peersMsgData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// peers msg pretty printer
|
// peers msg pretty printer
|
||||||
func (self *peersMsgData) String() string {
|
func (data *peersMsgData) String() string {
|
||||||
var from string
|
var from string
|
||||||
if self.from == nil {
|
if data.from == nil {
|
||||||
from = "ourselves"
|
from = "ourselves"
|
||||||
} else {
|
} else {
|
||||||
from = self.from.Addr().String()
|
from = data.from.Addr().String()
|
||||||
}
|
}
|
||||||
var target []byte
|
var target []byte
|
||||||
if len(self.Key) > 3 {
|
if len(data.Key) > 3 {
|
||||||
target = self.Key[:4]
|
target = data.Key[:4]
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, self.Id, self.Peers)
|
return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, data.Id, data.Peers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peersMsgData) setTimeout(t *time.Time) {
|
func (data *peersMsgData) setTimeout(t *time.Time) {
|
||||||
self.timeout = t
|
data.timeout = t
|
||||||
if t != nil {
|
if t != nil {
|
||||||
self.Timeout = uint64(t.UnixNano())
|
data.Timeout = uint64(t.UnixNano())
|
||||||
} else {
|
} else {
|
||||||
self.Timeout = 0
|
data.Timeout = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,8 +248,8 @@ type syncRequestMsgData struct {
|
||||||
SyncState *syncState `rlp:"nil"`
|
SyncState *syncState `rlp:"nil"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syncRequestMsgData) String() string {
|
func (data *syncRequestMsgData) String() string {
|
||||||
return fmt.Sprintf("%v", self.SyncState)
|
return fmt.Sprintf("%v", data.SyncState)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -265,8 +265,8 @@ type deliveryRequestMsgData struct {
|
||||||
Deliver []*syncRequest
|
Deliver []*syncRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *deliveryRequestMsgData) String() string {
|
func (data *deliveryRequestMsgData) String() string {
|
||||||
return fmt.Sprintf("sync request for new chunks\ndelivery request for %v chunks", len(self.Deliver))
|
return fmt.Sprintf("sync request for new chunks\ndelivery request for %v chunks", len(data.Deliver))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -287,8 +287,8 @@ type unsyncedKeysMsgData struct {
|
||||||
State *syncState
|
State *syncState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *unsyncedKeysMsgData) String() string {
|
func (data *unsyncedKeysMsgData) String() string {
|
||||||
return fmt.Sprintf("sync: keys of %d new chunks (state %v) => synced: %v", len(self.Unsynced), self.State, self.State.Synced)
|
return fmt.Sprintf("sync: keys of %d new chunks (state %v) => synced: %v", len(data.Unsynced), data.State, data.State.Synced)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -303,6 +303,6 @@ type paymentMsgData struct {
|
||||||
Promise *chequebook.Cheque // payment with cheque
|
Promise *chequebook.Cheque // payment with cheque
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *paymentMsgData) String() string {
|
func (data *paymentMsgData) String() string {
|
||||||
return fmt.Sprintf("payment for %d units: %v", self.Units, self.Promise)
|
return fmt.Sprintf("payment for %d units: %v", data.Units, data.Promise)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ the main protocol loop that
|
||||||
*/
|
*/
|
||||||
func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64, p *p2p.Peer, rw p2p.MsgReadWriter) (err error) {
|
func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64, p *p2p.Peer, rw p2p.MsgReadWriter) (err error) {
|
||||||
|
|
||||||
self := &bzz{
|
b := &bzz{
|
||||||
storage: depo,
|
storage: depo,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
hive: hive,
|
hive: hive,
|
||||||
|
|
@ -161,30 +161,30 @@ func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle handshake
|
// handle handshake
|
||||||
err = self.handleStatus()
|
err = b.handleStatus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
// if the handler loop exits, the peer is disconnecting
|
// if the handler loop exits, the peer is disconnecting
|
||||||
// deregister the peer in the hive
|
// deregister the peer in the hive
|
||||||
self.hive.removePeer(&peer{bzz: self})
|
b.hive.removePeer(&peer{bzz: b})
|
||||||
if self.syncer != nil {
|
if b.syncer != nil {
|
||||||
self.syncer.stop() // quits request db and delivery loops, save requests
|
b.syncer.stop() // quits request db and delivery loops, save requests
|
||||||
}
|
}
|
||||||
if self.swap != nil {
|
if b.swap != nil {
|
||||||
self.swap.Stop() // quits chequebox autocash etc
|
b.swap.Stop() // quits chequebox autocash etc
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// the main forever loop that handles incoming requests
|
// the main forever loop that handles incoming requests
|
||||||
for {
|
for {
|
||||||
if self.hive.blockRead {
|
if b.hive.blockRead {
|
||||||
log.Warn(fmt.Sprintf("Cannot read network"))
|
log.Warn(fmt.Sprintf("Cannot read network"))
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = self.handle()
|
err = b.handle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -193,13 +193,13 @@ func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook
|
||||||
|
|
||||||
// TODO: may need to implement protocol drop only? don't want to kick off the peer
|
// TODO: may need to implement protocol drop only? don't want to kick off the peer
|
||||||
// if they are useful for other protocols
|
// if they are useful for other protocols
|
||||||
func (self *bzz) Drop() {
|
func (b *bzz) Drop() {
|
||||||
self.peer.Disconnect(p2p.DiscSubprotocolError)
|
b.peer.Disconnect(p2p.DiscSubprotocolError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// one cycle of the main forever loop that handles and dispatches incoming messages
|
// one cycle of the main forever loop that handles and dispatches incoming messages
|
||||||
func (self *bzz) handle() error {
|
func (b *bzz) handle() error {
|
||||||
msg, err := self.rw.ReadMsg()
|
msg, err := b.rw.ReadMsg()
|
||||||
log.Debug(fmt.Sprintf("<- %v", msg))
|
log.Debug(fmt.Sprintf("<- %v", msg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -229,10 +229,10 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<- %v: Data too short (%v)", msg, n)
|
return fmt.Errorf("<- %v: Data too short (%v)", msg, n)
|
||||||
}
|
}
|
||||||
// last Active time is set only when receiving chunks
|
// last Active time is set only when receiving chunks
|
||||||
self.lastActive = time.Now()
|
b.lastActive = time.Now()
|
||||||
log.Trace(fmt.Sprintf("incoming store request: %s", req.String()))
|
log.Trace(fmt.Sprintf("incoming store request: %s", req.String()))
|
||||||
// swap accounting is done within forwarding
|
// swap accounting is done within forwarding
|
||||||
self.storage.HandleStoreRequestMsg(&req, &peer{bzz: self})
|
b.storage.HandleStoreRequestMsg(&req, &peer{bzz: b})
|
||||||
|
|
||||||
case retrieveRequestMsg:
|
case retrieveRequestMsg:
|
||||||
// retrieve Requests are dispatched to netStore
|
// retrieve Requests are dispatched to netStore
|
||||||
|
|
@ -241,18 +241,18 @@ func (self *bzz) handle() error {
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
req.from = &peer{bzz: self}
|
req.from = &peer{bzz: b}
|
||||||
// if request is lookup and not to be delivered
|
// if request is lookup and not to be delivered
|
||||||
if req.isLookup() {
|
if req.isLookup() {
|
||||||
log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from))
|
log.Trace(fmt.Sprintf("b lookup for %v: responding with peers only...", req.from))
|
||||||
} else if req.Key == nil {
|
} else if req.Key == nil {
|
||||||
return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil")
|
return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil")
|
||||||
} else {
|
} else {
|
||||||
// swap accounting is done within netStore
|
// swap accounting is done within netStore
|
||||||
self.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: self})
|
b.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: b})
|
||||||
}
|
}
|
||||||
// direct response with peers, TODO: sort this out
|
// direct response with peers, TODO: sort this out
|
||||||
self.hive.peers(&req)
|
b.hive.peers(&req)
|
||||||
|
|
||||||
case peersMsg:
|
case peersMsg:
|
||||||
// response to lookups and immediate response to retrieve requests
|
// response to lookups and immediate response to retrieve requests
|
||||||
|
|
@ -262,9 +262,9 @@ func (self *bzz) handle() error {
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
req.from = &peer{bzz: self}
|
req.from = &peer{bzz: b}
|
||||||
log.Trace(fmt.Sprintf("<- peer addresses: %v", req))
|
log.Trace(fmt.Sprintf("<- peer addresses: %v", req))
|
||||||
self.hive.HandlePeersMsg(&req, &peer{bzz: self})
|
b.hive.HandlePeersMsg(&req, &peer{bzz: b})
|
||||||
|
|
||||||
case syncRequestMsg:
|
case syncRequestMsg:
|
||||||
syncRequestMsgCounter.Inc(1)
|
syncRequestMsgCounter.Inc(1)
|
||||||
|
|
@ -273,8 +273,8 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- sync request: %v", req))
|
log.Debug(fmt.Sprintf("<- sync request: %v", req))
|
||||||
self.lastActive = time.Now()
|
b.lastActive = time.Now()
|
||||||
self.sync(req.SyncState)
|
b.sync(req.SyncState)
|
||||||
|
|
||||||
case unsyncedKeysMsg:
|
case unsyncedKeysMsg:
|
||||||
// coming from parent node offering
|
// coming from parent node offering
|
||||||
|
|
@ -284,8 +284,8 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String()))
|
log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String()))
|
||||||
err := self.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: self})
|
err := b.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: b})
|
||||||
self.lastActive = time.Now()
|
b.lastActive = time.Now()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
@ -299,8 +299,8 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<-msg %v: %v", msg, err)
|
return fmt.Errorf("<-msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- delivery request: %s", req.String()))
|
log.Debug(fmt.Sprintf("<- delivery request: %s", req.String()))
|
||||||
err := self.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: self})
|
err := b.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: b})
|
||||||
self.lastActive = time.Now()
|
b.lastActive = time.Now()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
@ -308,13 +308,13 @@ func (self *bzz) handle() error {
|
||||||
case paymentMsg:
|
case paymentMsg:
|
||||||
// swap protocol message for payment, Units paid for, Cheque paid with
|
// swap protocol message for payment, Units paid for, Cheque paid with
|
||||||
paymentMsgCounter.Inc(1)
|
paymentMsgCounter.Inc(1)
|
||||||
if self.swapEnabled {
|
if b.swapEnabled {
|
||||||
var req paymentMsgData
|
var req paymentMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- payment: %s", req.String()))
|
log.Debug(fmt.Sprintf("<- payment: %s", req.String()))
|
||||||
self.swap.Receive(int(req.Units), req.Promise)
|
b.swap.Receive(int(req.Units), req.Promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -325,27 +325,27 @@ func (self *bzz) handle() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) handleStatus() (err error) {
|
func (b *bzz) handleStatus() (err error) {
|
||||||
|
|
||||||
handshake := &statusMsgData{
|
handshake := &statusMsgData{
|
||||||
Version: uint64(Version),
|
Version: uint64(Version),
|
||||||
ID: "honey",
|
ID: "honey",
|
||||||
Addr: self.selfAddr(),
|
Addr: b.bAddr(),
|
||||||
NetworkId: self.NetworkId,
|
NetworkId: b.NetworkId,
|
||||||
Swap: &bzzswap.SwapProfile{
|
Swap: &bzzswap.SwapProfile{
|
||||||
Profile: self.swapParams.Profile,
|
Profile: b.swapParams.Profile,
|
||||||
PayProfile: self.swapParams.PayProfile,
|
PayProfile: b.swapParams.PayProfile,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p2p.Send(self.rw, statusMsg, handshake)
|
err = p2p.Send(b.rw, statusMsg, handshake)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// read and handle remote status
|
// read and handle remote status
|
||||||
var msg p2p.Msg
|
var msg p2p.Msg
|
||||||
msg, err = self.rw.ReadMsg()
|
msg, err = b.rw.ReadMsg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -365,52 +365,52 @@ func (self *bzz) handleStatus() (err error) {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.NetworkId != self.NetworkId {
|
if status.NetworkId != b.NetworkId {
|
||||||
return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, self.NetworkId)
|
return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, b.NetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Version != status.Version {
|
if Version != status.Version {
|
||||||
return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version)
|
return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.remoteAddr = self.peerAddr(status.Addr)
|
b.remoteAddr = b.peerAddr(status.Addr)
|
||||||
log.Trace(fmt.Sprintf("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr()))
|
log.Trace(fmt.Sprintf("b: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", b.bAddr(), b.remoteAddr, b.peer.LocalAddr(), status.Addr.IP, b.peer.RemoteAddr()))
|
||||||
|
|
||||||
if self.swapEnabled {
|
if b.swapEnabled {
|
||||||
// set remote profile for accounting
|
// set remote profile for accounting
|
||||||
self.swap, err = bzzswap.NewSwap(self.swapParams, status.Swap, self.backend, self)
|
b.swap, err = bzzswap.NewSwap(b.swapParams, status.Swap, b.backend, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId))
|
log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", b.remoteAddr.Addr[:4], status.Version, status.NetworkId))
|
||||||
err = self.hive.addPeer(&peer{bzz: self})
|
err = b.hive.addPeer(&peer{bzz: b})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// hive sets syncstate so sync should start after node added
|
// hive sets syncstate so sync should start after node added
|
||||||
log.Info(fmt.Sprintf("syncronisation request sent with %v", self.syncState))
|
log.Info(fmt.Sprintf("syncronisation request sent with %v", b.syncState))
|
||||||
self.syncRequest()
|
b.syncRequest()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) sync(state *syncState) error {
|
func (b *bzz) sync(state *syncState) error {
|
||||||
// syncer setup
|
// syncer setup
|
||||||
if self.syncer != nil {
|
if b.syncer != nil {
|
||||||
return errors.New("sync request can only be sent once")
|
return errors.New("sync request can only be sent once")
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt := self.dbAccess.counter()
|
cnt := b.dbAccess.counter()
|
||||||
remoteaddr := self.remoteAddr.Addr
|
remoteaddr := b.remoteAddr.Addr
|
||||||
start, stop := self.hive.kad.KeyRange(remoteaddr)
|
start, stop := b.hive.kad.KeyRange(remoteaddr)
|
||||||
|
|
||||||
// an explicitly received nil syncstate disables syncronisation
|
// an explicitly received nil syncstate disables syncronisation
|
||||||
if state == nil {
|
if state == nil {
|
||||||
self.syncEnabled = false
|
b.syncEnabled = false
|
||||||
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", self))
|
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", b))
|
||||||
state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true}
|
state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true}
|
||||||
} else {
|
} else {
|
||||||
state.synced = make(chan bool)
|
state.synced = make(chan bool)
|
||||||
|
|
@ -419,45 +419,45 @@ func (self *bzz) sync(state *syncState) error {
|
||||||
state.Start = storage.Key(start[:])
|
state.Start = storage.Key(start[:])
|
||||||
state.Stop = storage.Key(stop[:])
|
state.Stop = storage.Key(stop[:])
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", self, state))
|
log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", b, state))
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
self.syncer, err = newSyncer(
|
b.syncer, err = newSyncer(
|
||||||
self.requestDb,
|
b.requestDb,
|
||||||
storage.Key(remoteaddr[:]),
|
storage.Key(remoteaddr[:]),
|
||||||
self.dbAccess,
|
b.dbAccess,
|
||||||
self.unsyncedKeys, self.store,
|
b.unsyncedKeys, b.store,
|
||||||
self.syncParams, state, func() bool { return self.syncEnabled },
|
b.syncParams, state, func() bool { return b.syncEnabled },
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("syncer set for peer %v", self))
|
log.Trace(fmt.Sprintf("syncer set for peer %v", b))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) String() string {
|
func (b *bzz) String() string {
|
||||||
return self.remoteAddr.String()
|
return b.remoteAddr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// repair reported address if IP missing
|
// repair reported address if IP missing
|
||||||
func (self *bzz) peerAddr(base *peerAddr) *peerAddr {
|
func (b *bzz) peerAddr(base *peerAddr) *peerAddr {
|
||||||
if base.IP.IsUnspecified() {
|
if base.IP.IsUnspecified() {
|
||||||
host, _, _ := net.SplitHostPort(self.peer.RemoteAddr().String())
|
host, _, _ := net.SplitHostPort(b.peer.RemoteAddr().String())
|
||||||
base.IP = net.ParseIP(host)
|
base.IP = net.ParseIP(host)
|
||||||
}
|
}
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns self advertised node connection info (listening address w enodes)
|
// returns b advertised node connection info (listening address w enodes)
|
||||||
// IP will get repaired on the other end if missing
|
// IP will get repaired on the other end if missing
|
||||||
// or resolved via ID by discovery at dialout
|
// or resolved via ID by discovery at dialout
|
||||||
func (self *bzz) selfAddr() *peerAddr {
|
func (b *bzz) bAddr() *peerAddr {
|
||||||
id := self.hive.id
|
id := b.hive.id
|
||||||
host, port, _ := net.SplitHostPort(self.hive.listenAddr())
|
host, port, _ := net.SplitHostPort(b.hive.listenAddr())
|
||||||
intport, _ := strconv.Atoi(port)
|
intport, _ := strconv.Atoi(port)
|
||||||
addr := &peerAddr{
|
addr := &peerAddr{
|
||||||
Addr: self.hive.addr,
|
Addr: b.hive.addr,
|
||||||
ID: id[:],
|
ID: id[:],
|
||||||
IP: net.ParseIP(host),
|
IP: net.ParseIP(host),
|
||||||
Port: uint16(intport),
|
Port: uint16(intport),
|
||||||
|
|
@ -467,68 +467,68 @@ func (self *bzz) selfAddr() *peerAddr {
|
||||||
|
|
||||||
// outgoing messages
|
// outgoing messages
|
||||||
// send retrieveRequestMsg
|
// send retrieveRequestMsg
|
||||||
func (self *bzz) retrieve(req *retrieveRequestMsgData) error {
|
func (b *bzz) retrieve(req *retrieveRequestMsgData) error {
|
||||||
return self.send(retrieveRequestMsg, req)
|
return b.send(retrieveRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send storeRequestMsg
|
// send storeRequestMsg
|
||||||
func (self *bzz) store(req *storeRequestMsgData) error {
|
func (b *bzz) store(req *storeRequestMsgData) error {
|
||||||
return self.send(storeRequestMsg, req)
|
return b.send(storeRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) syncRequest() error {
|
func (b *bzz) syncRequest() error {
|
||||||
req := &syncRequestMsgData{}
|
req := &syncRequestMsgData{}
|
||||||
if self.hive.syncEnabled {
|
if b.hive.syncEnabled {
|
||||||
log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", self, self.syncState))
|
log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", b, b.syncState))
|
||||||
req.SyncState = self.syncState
|
req.SyncState = b.syncState
|
||||||
}
|
}
|
||||||
if self.syncState == nil {
|
if b.syncState == nil {
|
||||||
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", self, self.syncState))
|
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", b, b.syncState))
|
||||||
}
|
}
|
||||||
return self.send(syncRequestMsg, req)
|
return b.send(syncRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue storeRequestMsg in request db
|
// queue storeRequestMsg in request db
|
||||||
func (self *bzz) deliveryRequest(reqs []*syncRequest) error {
|
func (b *bzz) deliveryRequest(reqs []*syncRequest) error {
|
||||||
req := &deliveryRequestMsgData{
|
req := &deliveryRequestMsgData{
|
||||||
Deliver: reqs,
|
Deliver: reqs,
|
||||||
}
|
}
|
||||||
return self.send(deliveryRequestMsg, req)
|
return b.send(deliveryRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// batch of syncRequests to send off
|
// batch of syncRequests to send off
|
||||||
func (self *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error {
|
func (b *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error {
|
||||||
req := &unsyncedKeysMsgData{
|
req := &unsyncedKeysMsgData{
|
||||||
Unsynced: reqs,
|
Unsynced: reqs,
|
||||||
State: state,
|
State: state,
|
||||||
}
|
}
|
||||||
return self.send(unsyncedKeysMsg, req)
|
return b.send(unsyncedKeysMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send paymentMsg
|
// send paymentMsg
|
||||||
func (self *bzz) Pay(units int, promise swap.Promise) {
|
func (b *bzz) Pay(units int, promise swap.Promise) {
|
||||||
req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)}
|
req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)}
|
||||||
self.payment(req)
|
b.payment(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send paymentMsg
|
// send paymentMsg
|
||||||
func (self *bzz) payment(req *paymentMsgData) error {
|
func (b *bzz) payment(req *paymentMsgData) error {
|
||||||
return self.send(paymentMsg, req)
|
return b.send(paymentMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sends peersMsg
|
// sends peersMsg
|
||||||
func (self *bzz) peers(req *peersMsgData) error {
|
func (b *bzz) peers(req *peersMsgData) error {
|
||||||
return self.send(peersMsg, req)
|
return b.send(peersMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) send(msg uint64, data interface{}) error {
|
func (b *bzz) send(msg uint64, data interface{}) error {
|
||||||
if self.hive.blockWrite {
|
if b.hive.blockWrite {
|
||||||
return fmt.Errorf("network write blocked")
|
return fmt.Errorf("network write blocked")
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, self))
|
log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, b))
|
||||||
err := p2p.Send(self.rw, msg, data)
|
err := p2p.Send(b.rw, msg, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Drop()
|
b.Drop()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,26 +108,26 @@ It is automatically started when syncdb is initialised.
|
||||||
|
|
||||||
It saves the buffer to db upon receiving quit signal. syncDb#stop()
|
It saves the buffer to db upon receiving quit signal. syncDb#stop()
|
||||||
*/
|
*/
|
||||||
func (self *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) {
|
func (db *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) {
|
||||||
var buffer, db chan interface{} // channels representing the two read modes
|
var buffer, dbChan chan interface{} // channels representing the two read modes
|
||||||
var more bool
|
var more bool
|
||||||
var req interface{}
|
var req interface{}
|
||||||
var entry *syncDbEntry
|
var entry *syncDbEntry
|
||||||
var inBatch, inDb int
|
var inBatch, inDb int
|
||||||
batch := new(leveldb.Batch)
|
batch := new(leveldb.Batch)
|
||||||
var dbSize chan int
|
var dbSize chan int
|
||||||
quit := self.quit
|
quit := db.quit
|
||||||
counterValue := make([]byte, 8)
|
counterValue := make([]byte, 8)
|
||||||
|
|
||||||
// counter is used for keeping the items in order, persisted to db
|
// counter is used for keeping the items in order, persisted to db
|
||||||
// start counter where db was at, 0 if not found
|
// start counter where db was at, 0 if not found
|
||||||
data, err := self.db.Get(self.counterKey)
|
data, err := db.db.Get(db.counterKey)
|
||||||
var counter uint64
|
var counter uint64
|
||||||
if err == nil {
|
if err == nil {
|
||||||
counter = binary.BigEndian.Uint64(data)
|
counter = binary.BigEndian.Uint64(data)
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter read from db at %v", self.key.Log(), self.priority, counter))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter read from db at %v", db.key.Log(), db.priority, counter))
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter starts at %v", self.key.Log(), self.priority, counter))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter starts at %v", db.key.Log(), db.priority, counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
LOOP:
|
LOOP:
|
||||||
|
|
@ -139,58 +139,58 @@ LOOP:
|
||||||
// deliver request : this is blocking on network write so
|
// deliver request : this is blocking on network write so
|
||||||
// it is passed the quit channel as argument, so that it returns
|
// it is passed the quit channel as argument, so that it returns
|
||||||
// if syncdb is stopped. In this case we need to save the item to the db
|
// if syncdb is stopped. In this case we need to save the item to the db
|
||||||
more = deliver(req, self.quit)
|
more = deliver(req, db.quit)
|
||||||
if !more {
|
if !more {
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", db.key.Log(), db.priority, db.dbTotal, db.total))
|
||||||
// received quit signal, save request currently waiting delivery
|
// received quit signal, save request currently waiting delivery
|
||||||
// by switching to db mode and closing the buffer
|
// by switching to db mode and closing the buffer
|
||||||
buffer = nil
|
buffer = nil
|
||||||
db = self.buffer
|
dbChan = db.buffer
|
||||||
close(db)
|
close(dbChan)
|
||||||
quit = nil // needs to block the quit case in select
|
quit = nil // needs to block the quit case in select
|
||||||
break // break from select, this item will be written to the db
|
break // break from select, this item will be written to the db
|
||||||
}
|
}
|
||||||
self.total++
|
db.total++
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] deliver (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] deliver (db/total): %v/%v", db.key.Log(), db.priority, db.dbTotal, db.total))
|
||||||
// by the time deliver returns, there were new writes to the buffer
|
// by the time deliver returns, there were new writes to the buffer
|
||||||
// if buffer contention is detected, switch to db mode which drains
|
// if buffer contention is detected, switch to db mode which drains
|
||||||
// the buffer so no process will block on pushing store requests
|
// the buffer so no process will block on pushing store requests
|
||||||
if len(buffer) == cap(buffer) {
|
if len(buffer) == cap(buffer) {
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, cap(buffer), self.dbTotal, self.total))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", db.key.Log(), db.priority, cap(buffer), db.dbTotal, db.total))
|
||||||
buffer = nil
|
buffer = nil
|
||||||
db = self.buffer
|
dbChan = db.buffer
|
||||||
}
|
}
|
||||||
continue LOOP
|
continue LOOP
|
||||||
|
|
||||||
// incoming entry to put into db
|
// incoming entry to put into db
|
||||||
case req, more = <-db:
|
case req, more = <-dbChan:
|
||||||
if !more {
|
if !more {
|
||||||
// only if quit is called, saved all the buffer
|
// only if quit is called, saved all the buffer
|
||||||
binary.BigEndian.PutUint64(counterValue, counter)
|
binary.BigEndian.PutUint64(counterValue, counter)
|
||||||
batch.Put(self.counterKey, counterValue) // persist counter in batch
|
batch.Put(db.counterKey, counterValue) // persist counter in batch
|
||||||
self.writeSyncBatch(batch) // save batch
|
db.writeSyncBatch(batch) // save batch
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save current batch to db", self.key.Log(), self.priority))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save current batch to db", db.key.Log(), db.priority))
|
||||||
break LOOP
|
break LOOP
|
||||||
}
|
}
|
||||||
self.dbTotal++
|
db.dbTotal++
|
||||||
self.total++
|
db.total++
|
||||||
// otherwise break after select
|
// otherwise break after select
|
||||||
case dbSize = <-self.batch:
|
case dbSize = <-db.batch:
|
||||||
// explicit request for batch
|
// explicit request for batch
|
||||||
if inBatch == 0 && quit != nil {
|
if inBatch == 0 && quit != nil {
|
||||||
// there was no writes since the last batch so db depleted
|
// there was no writes since the last batch so db depleted
|
||||||
// switch to buffer mode
|
// switch to buffer mode
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] empty db: switching to buffer", self.key.Log(), self.priority))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] empty db: switching to buffer", db.key.Log(), db.priority))
|
||||||
db = nil
|
dbChan = nil
|
||||||
buffer = self.buffer
|
buffer = db.buffer
|
||||||
dbSize <- 0 // indicates to 'caller' that batch has been written
|
dbSize <- 0 // indicates to 'caller' that batch has been written
|
||||||
inDb = 0
|
inDb = 0
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
binary.BigEndian.PutUint64(counterValue, counter)
|
binary.BigEndian.PutUint64(counterValue, counter)
|
||||||
batch.Put(self.counterKey, counterValue)
|
batch.Put(db.counterKey, counterValue)
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] write batch %v/%v - %x - %x", self.key.Log(), self.priority, inBatch, counter, self.counterKey, counterValue))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] write batch %v/%v - %x - %x", db.key.Log(), db.priority, inBatch, counter, db.counterKey, counterValue))
|
||||||
batch = self.writeSyncBatch(batch)
|
batch = db.writeSyncBatch(batch)
|
||||||
dbSize <- inBatch // indicates to 'caller' that batch has been written
|
dbSize <- inBatch // indicates to 'caller' that batch has been written
|
||||||
inBatch = 0
|
inBatch = 0
|
||||||
continue LOOP
|
continue LOOP
|
||||||
|
|
@ -198,45 +198,45 @@ LOOP:
|
||||||
// closing syncDb#quit channel is used to signal to all goroutines to quit
|
// closing syncDb#quit channel is used to signal to all goroutines to quit
|
||||||
case <-quit:
|
case <-quit:
|
||||||
// need to save backlog, so switch to db mode
|
// need to save backlog, so switch to db mode
|
||||||
db = self.buffer
|
dbChan = db.buffer
|
||||||
buffer = nil
|
buffer = nil
|
||||||
quit = nil
|
quit = nil
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save buffer to db", self.key.Log(), self.priority))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save buffer to db", db.key.Log(), db.priority))
|
||||||
close(db)
|
close(dbChan)
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
// only get here if we put req into db
|
// only get here if we put req into db
|
||||||
entry, err = self.newSyncDbEntry(req, counter)
|
entry, err = db.newSyncDbEntry(req, counter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", self.key.Log(), self.priority, req, inBatch, inDb, err))
|
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", db.key.Log(), db.priority, req, inBatch, inDb, err))
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
batch.Put(entry.key, entry.val)
|
batch.Put(entry.key, entry.val)
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", self.key.Log(), self.priority, req, entry, inBatch, inDb, counter))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", db.key.Log(), db.priority, req, entry, inBatch, inDb, counter))
|
||||||
// if just switched to db mode and not quitting, then launch dbRead
|
// if just switched to db mode and not quitting, then launch dbRead
|
||||||
// in a parallel go routine to send deliveries from db
|
// in a parallel go routine to send deliveries from db
|
||||||
if inDb == 0 && quit != nil {
|
if inDb == 0 && quit != nil {
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] start dbRead", self.key.Log(), self.priority))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] start dbRead", db.key.Log(), db.priority))
|
||||||
go self.dbRead(true, counter, deliver)
|
go db.dbRead(true, counter, deliver)
|
||||||
}
|
}
|
||||||
inDb++
|
inDb++
|
||||||
inBatch++
|
inBatch++
|
||||||
counter++
|
counter++
|
||||||
// need to save the batch if it gets too large (== dbBatchSize)
|
// need to save the batch if it gets too large (== dbBatchSize)
|
||||||
if inBatch%int(self.dbBatchSize) == 0 {
|
if inBatch%int(db.dbBatchSize) == 0 {
|
||||||
batch = self.writeSyncBatch(batch)
|
batch = db.writeSyncBatch(batch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("syncDb[%v:%v]: saved %v keys (saved counter at %v)", self.key.Log(), self.priority, inBatch, counter))
|
log.Info(fmt.Sprintf("syncDb[%v:%v]: saved %v keys (saved counter at %v)", db.key.Log(), db.priority, inBatch, counter))
|
||||||
close(self.done)
|
close(db.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writes the batch to the db and returns a new batch object
|
// writes the batch to the db and returns a new batch object
|
||||||
func (self *syncDb) writeSyncBatch(batch *leveldb.Batch) *leveldb.Batch {
|
func (db *syncDb) writeSyncBatch(batch *leveldb.Batch) *leveldb.Batch {
|
||||||
err := self.db.Write(batch)
|
err := db.db.Write(batch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving batch to db failed: %v", self.key.Log(), self.priority, err))
|
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving batch to db failed: %v", db.key.Log(), db.priority, err))
|
||||||
return batch
|
return batch
|
||||||
}
|
}
|
||||||
return new(leveldb.Batch)
|
return new(leveldb.Batch)
|
||||||
|
|
@ -247,8 +247,8 @@ type syncDbEntry struct {
|
||||||
key, val []byte
|
key, val []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self syncDbEntry) String() string {
|
func (entry syncDbEntry) String() string {
|
||||||
return fmt.Sprintf("key: %x, value: %x", self.key, self.val)
|
return fmt.Sprintf("key: %x, value: %x", entry.key, entry.val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -272,9 +272,9 @@ dbRead needs a boolean to indicate if on first round all the historical
|
||||||
record is synced. Second argument to indicate current db counter
|
record is synced. Second argument to indicate current db counter
|
||||||
The third is the function to apply
|
The third is the function to apply
|
||||||
*/
|
*/
|
||||||
func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}, chan bool) bool) {
|
func (db *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}, chan bool) bool) {
|
||||||
key := make([]byte, 42)
|
key := make([]byte, 42)
|
||||||
copy(key, self.start)
|
copy(key, db.start)
|
||||||
binary.BigEndian.PutUint64(key[34:], counter)
|
binary.BigEndian.PutUint64(key[34:], counter)
|
||||||
var batches, n, cnt, total int
|
var batches, n, cnt, total int
|
||||||
var more bool
|
var more bool
|
||||||
|
|
@ -290,8 +290,8 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
|
||||||
// so that loop is not blocking while delivering
|
// so that loop is not blocking while delivering
|
||||||
// only relevant if cnt is large
|
// only relevant if cnt is large
|
||||||
select {
|
select {
|
||||||
case self.batch <- batchSizes:
|
case db.batch <- batchSizes:
|
||||||
case <-self.quit:
|
case <-db.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// wait for the write to finish and get the item count in the next batch
|
// wait for the write to finish and get the item count in the next batch
|
||||||
|
|
@ -302,31 +302,31 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it = self.db.NewIterator()
|
it = db.db.NewIterator()
|
||||||
it.Seek(key)
|
it.Seek(key)
|
||||||
if !it.Valid() {
|
if !it.Valid() {
|
||||||
copy(key, self.start)
|
copy(key, db.start)
|
||||||
useBatches = true
|
useBatches = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
del = new(leveldb.Batch)
|
del = new(leveldb.Batch)
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", self.key.Log(), self.priority, key, batches, cnt))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", db.key.Log(), db.priority, key, batches, cnt))
|
||||||
|
|
||||||
for n = 0; !useBatches || n < cnt; it.Next() {
|
for n = 0; !useBatches || n < cnt; it.Next() {
|
||||||
copy(key, it.Key())
|
copy(key, it.Key())
|
||||||
if len(key) == 0 || key[0] != 0 {
|
if len(key) == 0 || key[0] != 0 {
|
||||||
copy(key, self.start)
|
copy(key, db.start)
|
||||||
useBatches = true
|
useBatches = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
val := make([]byte, 40)
|
val := make([]byte, 40)
|
||||||
copy(val, it.Value())
|
copy(val, it.Value())
|
||||||
entry = &syncDbEntry{key, val}
|
entry = &syncDbEntry{key, val}
|
||||||
// log.Trace(fmt.Sprintf("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, self.key.Log(), batches, total, self.dbTotal, self.total))
|
// log.Trace(fmt.Sprintf("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", db.key.Log(), db.priority, db.key.Log(), batches, total, db.dbTotal, db.total))
|
||||||
more = fun(entry, self.quit)
|
more = fun(entry, db.quit)
|
||||||
if !more {
|
if !more {
|
||||||
// quit received when waiting to deliver entry, the entry will not be deleted
|
// quit received when waiting to deliver entry, the entry will not be deleted
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] batch %v quit after %v/%v items", self.key.Log(), self.priority, batches, n, cnt))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] batch %v quit after %v/%v items", db.key.Log(), db.priority, batches, n, cnt))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// since subsequent batches of the same db session are indexed incrementally
|
// since subsequent batches of the same db session are indexed incrementally
|
||||||
|
|
@ -336,22 +336,22 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
|
||||||
n++
|
n++
|
||||||
total++
|
total++
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, batches, total, self.dbTotal, self.total))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", db.key.Log(), db.priority, batches, total, db.dbTotal, db.total))
|
||||||
self.db.Write(del) // this could be async called only when db is idle
|
db.db.Write(del) // this could be async called only when db is idle
|
||||||
it.Release()
|
it.Release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
func (self *syncDb) stop() {
|
func (db *syncDb) stop() {
|
||||||
close(self.quit)
|
close(db.quit)
|
||||||
<-self.done
|
<-db.done
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate a dbkey for the request, for the db to work
|
// calculate a dbkey for the request, for the db to work
|
||||||
// see syncdb for db key structure
|
// see syncdb for db key structure
|
||||||
// polimorphic: accepted types, see syncer#addRequest
|
// polimorphic: accepted types, see syncer#addRequest
|
||||||
func (self *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *syncDbEntry, err error) {
|
func (db *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *syncDbEntry, err error) {
|
||||||
var key storage.Key
|
var key storage.Key
|
||||||
var chunk *storage.Chunk
|
var chunk *storage.Chunk
|
||||||
var id uint64
|
var id uint64
|
||||||
|
|
@ -377,7 +377,7 @@ func (self *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *sync
|
||||||
dbval := make([]byte, 40)
|
dbval := make([]byte, 40)
|
||||||
|
|
||||||
// encode key
|
// encode key
|
||||||
copy(dbkey[:], self.start[:34]) // db peer
|
copy(dbkey[:], db.start[:34]) // db peer
|
||||||
binary.BigEndian.PutUint64(dbkey[34:], counter)
|
binary.BigEndian.PutUint64(dbkey[34:], counter)
|
||||||
// encode value
|
// encode value
|
||||||
copy(dbval, key[:])
|
copy(dbval, key[:])
|
||||||
|
|
|
||||||
|
|
@ -53,43 +53,43 @@ func newTestSyncDb(priority, bufferSize, batchSize int, dbdir string, t *testing
|
||||||
}
|
}
|
||||||
dbdir = tmp
|
dbdir = tmp
|
||||||
}
|
}
|
||||||
db, err := storage.NewLDBDatabase(filepath.Join(dbdir, "requestdb"))
|
database, err := storage.NewLDBDatabase(filepath.Join(dbdir, "requestdb"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create db: %v", err)
|
t.Fatalf("unable to create db: %v", err)
|
||||||
}
|
}
|
||||||
self := &testSyncDb{
|
db := &testSyncDb{
|
||||||
fromDb: make(chan bool),
|
fromDb: make(chan bool),
|
||||||
dbdir: dbdir,
|
dbdir: dbdir,
|
||||||
t: t,
|
t: t,
|
||||||
}
|
}
|
||||||
h := crypto.Keccak256Hash([]byte{0})
|
h := crypto.Keccak256Hash([]byte{0})
|
||||||
key := storage.Key(h[:])
|
key := storage.Key(h[:])
|
||||||
self.syncDb = newSyncDb(db, key, uint(priority), uint(bufferSize), uint(batchSize), self.deliver)
|
db.syncDb = newSyncDb(database, key, uint(priority), uint(bufferSize), uint(batchSize), db.deliver)
|
||||||
// kick off db iterator right away, if no items on db this will allow
|
// kick off db iterator right away, if no items on db this will allow
|
||||||
// reading from the buffer
|
// reading from the buffer
|
||||||
return self
|
return db
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) close() {
|
func (db *testSyncDb) close() {
|
||||||
self.db.Close()
|
db.db.Close()
|
||||||
os.RemoveAll(self.dbdir)
|
os.RemoveAll(db.dbdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) push(n int) {
|
func (db *testSyncDb) push(n int) {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
self.buffer <- storage.Key(crypto.Keccak256([]byte{byte(self.c)}))
|
db.buffer <- storage.Key(crypto.Keccak256([]byte{byte(db.c)}))
|
||||||
self.sent = append(self.sent, self.c)
|
db.sent = append(db.sent, db.c)
|
||||||
self.c++
|
db.c++
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("pushed %v requests", n))
|
log.Debug(fmt.Sprintf("pushed %v requests", n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) draindb() {
|
func (db *testSyncDb) draindb() {
|
||||||
it := self.db.NewIterator()
|
it := db.db.NewIterator()
|
||||||
defer it.Release()
|
defer it.Release()
|
||||||
for {
|
for {
|
||||||
it.Seek(self.start)
|
it.Seek(db.start)
|
||||||
if !it.Valid() {
|
if !it.Valid() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -98,44 +98,44 @@ func (self *testSyncDb) draindb() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
it.Release()
|
it.Release()
|
||||||
it = self.db.NewIterator()
|
it = db.db.NewIterator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) deliver(req interface{}, quit chan bool) bool {
|
func (db *testSyncDb) deliver(req interface{}, quit chan bool) bool {
|
||||||
_, db := req.(*syncDbEntry)
|
_, entry := req.(*syncDbEntry)
|
||||||
key, _, _, _, err := parseRequest(req)
|
key, _, _, _, err := parseRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.t.Fatalf("unexpected error of key %v: %v", key, err)
|
db.t.Fatalf("unexpected error of key %v: %v", key, err)
|
||||||
}
|
}
|
||||||
self.delivered = append(self.delivered, key)
|
db.delivered = append(db.delivered, key)
|
||||||
select {
|
select {
|
||||||
case self.fromDb <- db:
|
case db.fromDb <- entry:
|
||||||
return true
|
return true
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) expect(n int, db bool) {
|
func (db *testSyncDb) expect(n int, b bool) {
|
||||||
var ok bool
|
var ok bool
|
||||||
// for n items
|
// for n items
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
ok = <-self.fromDb
|
ok = <-db.fromDb
|
||||||
if self.at+1 > len(self.delivered) {
|
if db.at+1 > len(db.delivered) {
|
||||||
self.t.Fatalf("expected %v, got %v", self.at+1, len(self.delivered))
|
db.t.Fatalf("expected %v, got %v", db.at+1, len(db.delivered))
|
||||||
}
|
}
|
||||||
if len(self.sent) > self.at && !bytes.Equal(crypto.Keccak256([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) {
|
if len(db.sent) > db.at && !bytes.Equal(crypto.Keccak256([]byte{byte(db.sent[db.at])}), db.delivered[db.at]) {
|
||||||
self.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db)
|
db.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, db.at, db.sent[db.at], ok, db)
|
||||||
log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db))
|
log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, db.at, db.sent[db.at], ok, db))
|
||||||
}
|
}
|
||||||
if !ok && db {
|
if !ok && b {
|
||||||
self.t.Fatalf("expected delivery %v/%v/%v from db", i, n, self.at)
|
db.t.Fatalf("expected delivery %v/%v/%v from db", i, n, db.at)
|
||||||
}
|
}
|
||||||
if ok && !db {
|
if ok && !b {
|
||||||
self.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, self.at)
|
db.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, db.at)
|
||||||
}
|
}
|
||||||
self.at++
|
db.at++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,13 +77,13 @@ func NewDbAccess(loc *storage.LocalStore) *DbAccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
// to obtain the chunks from key or request db entry only
|
// to obtain the chunks from key or request db entry only
|
||||||
func (self *DbAccess) get(key storage.Key) (*storage.Chunk, error) {
|
func (access *DbAccess) get(key storage.Key) (*storage.Chunk, error) {
|
||||||
return self.loc.Get(key)
|
return access.loc.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// current storage counter of chunk db
|
// current storage counter of chunk db
|
||||||
func (self *DbAccess) counter() uint64 {
|
func (access *DbAccess) counter() uint64 {
|
||||||
return self.db.Counter()
|
return access.db.Counter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// implemented by dbStoreSyncIterator
|
// implemented by dbStoreSyncIterator
|
||||||
|
|
@ -92,28 +92,28 @@ type keyIterator interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generator function for iteration by address range and storage counter
|
// generator function for iteration by address range and storage counter
|
||||||
func (self *DbAccess) iterator(s *syncState) keyIterator {
|
func (access *DbAccess) iterator(s *syncState) keyIterator {
|
||||||
it, err := self.db.NewSyncIterator(*(s.DbSyncState))
|
it, err := access.db.NewSyncIterator(*(s.DbSyncState))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return keyIterator(it)
|
return keyIterator(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self syncState) String() string {
|
func (state syncState) String() string {
|
||||||
if self.Synced {
|
if state.Synced {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"session started at: %v, last seen at: %v, latest key: %v",
|
"session started at: %v, last seen at: %v, latest key: %v",
|
||||||
self.SessionAt, self.LastSeenAt,
|
state.SessionAt, state.LastSeenAt,
|
||||||
self.Latest.Log(),
|
state.Latest.Log(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"address: %v-%v, index: %v-%v, session started at: %v, last seen at: %v, latest key: %v",
|
"address: %v-%v, index: %v-%v, session started at: %v, last seen at: %v, latest key: %v",
|
||||||
self.Start.Log(), self.Stop.Log(),
|
state.Start.Log(), state.Stop.Log(),
|
||||||
self.First, self.Last,
|
state.First, state.Last,
|
||||||
self.SessionAt, self.LastSeenAt,
|
state.SessionAt, state.LastSeenAt,
|
||||||
self.Latest.Log(),
|
state.Latest.Log(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -145,8 +145,8 @@ func NewDefaultSyncParams() *SyncParams {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *SyncParams) Init(path string) {
|
func (params *SyncParams) Init(path string) {
|
||||||
self.RequestDbPath = filepath.Join(path, "requests")
|
params.RequestDbPath = filepath.Join(path, "requests")
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncer is the agent that manages content distribution/storage replication/chunk storeRequest forwarding
|
// syncer is the agent that manages content distribution/storage replication/chunk storeRequest forwarding
|
||||||
|
|
@ -191,7 +191,7 @@ func newSyncer(
|
||||||
keyBufferSize := params.KeyBufferSize
|
keyBufferSize := params.KeyBufferSize
|
||||||
dbBatchSize := params.RequestDbBatchSize
|
dbBatchSize := params.RequestDbBatchSize
|
||||||
|
|
||||||
self := &syncer{
|
syncer := &syncer{
|
||||||
syncF: syncF,
|
syncF: syncF,
|
||||||
key: remotekey,
|
key: remotekey,
|
||||||
dbAccess: dbAccess,
|
dbAccess: dbAccess,
|
||||||
|
|
@ -207,22 +207,22 @@ func newSyncer(
|
||||||
|
|
||||||
// initialising
|
// initialising
|
||||||
for i := 0; i < priorities; i++ {
|
for i := 0; i < priorities; i++ {
|
||||||
self.keys[i] = make(chan interface{}, keyBufferSize)
|
syncer.keys[i] = make(chan interface{}, keyBufferSize)
|
||||||
self.deliveries[i] = make(chan *storeRequestMsgData)
|
syncer.deliveries[i] = make(chan *storeRequestMsgData)
|
||||||
// initialise a syncdb instance for each priority queue
|
// initialise a syncdb instance for each priority queue
|
||||||
self.queues[i] = newSyncDb(db, remotekey, uint(i), syncBufferSize, dbBatchSize, self.deliver(uint(i)))
|
syncer.queues[i] = newSyncDb(db, remotekey, uint(i), syncBufferSize, dbBatchSize, syncer.deliver(uint(i)))
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("syncer started: %v", state))
|
log.Info(fmt.Sprintf("syncer started: %v", state))
|
||||||
// launch chunk delivery service
|
// launch chunk delivery service
|
||||||
go self.syncDeliveries()
|
go syncer.syncDeliveries()
|
||||||
// launch sync task manager
|
// launch sync task manager
|
||||||
if self.syncF() {
|
if syncer.syncF() {
|
||||||
go self.sync()
|
go syncer.sync()
|
||||||
}
|
}
|
||||||
// process unsynced keys to broadcast
|
// process unsynced keys to broadcast
|
||||||
go self.syncUnsyncedKeys()
|
go syncer.syncUnsyncedKeys()
|
||||||
|
|
||||||
return self, nil
|
return syncer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// metadata serialisation
|
// metadata serialisation
|
||||||
|
|
@ -266,21 +266,21 @@ func decodeSync(meta *json.RawMessage) (*syncState, error) {
|
||||||
|
|
||||||
sync is called from the syncer constructor and is not supposed to be used externally
|
sync is called from the syncer constructor and is not supposed to be used externally
|
||||||
*/
|
*/
|
||||||
func (self *syncer) sync() {
|
func (s *syncer) sync() {
|
||||||
state := self.state
|
state := s.state
|
||||||
// sync finished
|
// sync finished
|
||||||
defer close(self.syncStates)
|
defer close(s.syncStates)
|
||||||
|
|
||||||
// 0. first replay stale requests from request db
|
// 0. first replay stale requests from request db
|
||||||
if state.SessionAt == 0 {
|
if state.SessionAt == 0 {
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", self.key.Log()))
|
log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", s.key.Log()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", self.key.Log()))
|
log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", s.key.Log()))
|
||||||
for p := priorities - 1; p >= 0; p-- {
|
for p := priorities - 1; p >= 0; p-- {
|
||||||
self.queues[p].dbRead(false, 0, self.replay())
|
s.queues[p].dbRead(false, 0, s.replay())
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", self.key.Log()))
|
log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", s.key.Log()))
|
||||||
|
|
||||||
// unless peer is synced sync unfinished history beginning on
|
// unless peer is synced sync unfinished history beginning on
|
||||||
if !state.Synced {
|
if !state.Synced {
|
||||||
|
|
@ -289,9 +289,9 @@ func (self *syncer) sync() {
|
||||||
if !storage.IsZeroKey(state.Latest) {
|
if !storage.IsZeroKey(state.Latest) {
|
||||||
// 1. there is unfinished earlier sync
|
// 1. there is unfinished earlier sync
|
||||||
state.Start = state.Latest
|
state.Start = state.Latest
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", self.key.Log(), state))
|
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", s.key.Log(), state))
|
||||||
// blocks while the entire history upto state is synced
|
// blocks while the entire history upto state is synced
|
||||||
self.syncState(state)
|
s.syncState(state)
|
||||||
if state.Last < state.SessionAt {
|
if state.Last < state.SessionAt {
|
||||||
state.First = state.Last + 1
|
state.First = state.Last + 1
|
||||||
}
|
}
|
||||||
|
|
@ -301,8 +301,8 @@ func (self *syncer) sync() {
|
||||||
// 2. sync up to last disconnect1
|
// 2. sync up to last disconnect1
|
||||||
if state.First < state.LastSeenAt {
|
if state.First < state.LastSeenAt {
|
||||||
state.Last = state.LastSeenAt
|
state.Last = state.LastSeenAt
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", self.key.Log(), state.LastSeenAt, state))
|
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", s.key.Log(), state.LastSeenAt, state))
|
||||||
self.syncState(state)
|
s.syncState(state)
|
||||||
state.First = state.LastSeenAt
|
state.First = state.LastSeenAt
|
||||||
}
|
}
|
||||||
state.Latest = storage.ZeroKey
|
state.Latest = storage.ZeroKey
|
||||||
|
|
@ -316,28 +316,28 @@ func (self *syncer) sync() {
|
||||||
// if there have been new chunks since last session
|
// if there have been new chunks since last session
|
||||||
if state.LastSeenAt < state.SessionAt {
|
if state.LastSeenAt < state.SessionAt {
|
||||||
state.Last = state.SessionAt
|
state.Last = state.SessionAt
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", self.key.Log(), state.LastSeenAt, state.SessionAt, state))
|
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", s.key.Log(), state.LastSeenAt, state.SessionAt, state))
|
||||||
// blocks until state syncing is finished
|
// blocks until state syncing is finished
|
||||||
self.syncState(state)
|
s.syncState(state)
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", self.key.Log()))
|
log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", s.key.Log()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait till syncronised block uptil state is synced
|
// wait till syncronised block uptil state is synced
|
||||||
func (self *syncer) syncState(state *syncState) {
|
func (s *syncer) syncState(state *syncState) {
|
||||||
self.syncStates <- state
|
s.syncStates <- state
|
||||||
select {
|
select {
|
||||||
case <-state.synced:
|
case <-state.synced:
|
||||||
case <-self.quit:
|
case <-s.quit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop quits both request processor and saves the request cache to disk
|
// stop quits both request processor and saves the request cache to disk
|
||||||
func (self *syncer) stop() {
|
func (s *syncer) stop() {
|
||||||
close(self.quit)
|
close(s.quit)
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", s.key.Log()))
|
||||||
for _, db := range self.queues {
|
for _, db := range s.queues {
|
||||||
db.stop()
|
db.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -348,11 +348,11 @@ type syncRequest struct {
|
||||||
Priority uint
|
Priority uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syncRequest) String() string {
|
func (req *syncRequest) String() string {
|
||||||
return fmt.Sprintf("<Key: %v, Priority: %v>", self.Key.Log(), self.Priority)
|
return fmt.Sprintf("<Key: %v, Priority: %v>", req.Key.Log(), req.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error) {
|
func (s *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error) {
|
||||||
key, _, _, _, err := parseRequest(req)
|
key, _, _, _, err := parseRequest(req)
|
||||||
// TODO: if req has chunk, it should be put in a cache
|
// TODO: if req has chunk, it should be put in a cache
|
||||||
// create
|
// create
|
||||||
|
|
@ -366,11 +366,11 @@ func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error)
|
||||||
// * read is on demand, blocking unless history channel is read
|
// * read is on demand, blocking unless history channel is read
|
||||||
// * accepts sync requests (syncStates) to create new db iterator
|
// * accepts sync requests (syncStates) to create new db iterator
|
||||||
// * closes the channel one iteration finishes
|
// * closes the channel one iteration finishes
|
||||||
func (self *syncer) syncHistory(state *syncState) chan interface{} {
|
func (s *syncer) syncHistory(state *syncState) chan interface{} {
|
||||||
var n uint
|
var n uint
|
||||||
history := make(chan interface{})
|
history := make(chan interface{})
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", self.key.Log(), state.First, state.Last, state.Start, state.Stop))
|
log.Debug(fmt.Sprintf("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", s.key.Log(), state.First, state.Last, state.Start, state.Stop))
|
||||||
it := self.dbAccess.iterator(state)
|
it := s.dbAccess.iterator(state)
|
||||||
if it != nil {
|
if it != nil {
|
||||||
go func() {
|
go func() {
|
||||||
// signal end of the iteration ended
|
// signal end of the iteration ended
|
||||||
|
|
@ -385,22 +385,22 @@ func (self *syncer) syncHistory(state *syncState) chan interface{} {
|
||||||
// blocking until history channel is read from
|
// blocking until history channel is read from
|
||||||
case history <- key:
|
case history <- key:
|
||||||
n++
|
n++
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", self.key.Log(), key.Log(), n))
|
log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", s.key.Log(), key.Log(), n))
|
||||||
state.Latest = key
|
state.Latest = key
|
||||||
case <-self.quit:
|
case <-s.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", self.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n))
|
log.Debug(fmt.Sprintf("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", s.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n))
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
return history
|
return history
|
||||||
}
|
}
|
||||||
|
|
||||||
// triggers key syncronisation
|
// triggers key syncronisation
|
||||||
func (self *syncer) sendUnsyncedKeys() {
|
func (s *syncer) sendUnsyncedKeys() {
|
||||||
select {
|
select {
|
||||||
case self.deliveryRequest <- true:
|
case s.deliveryRequest <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -411,7 +411,7 @@ func (self *syncer) sendUnsyncedKeys() {
|
||||||
// historical data is used so historical items are lower priority within
|
// historical data is used so historical items are lower priority within
|
||||||
// their priority group.
|
// their priority group.
|
||||||
// * Order of historical data is unspecified
|
// * Order of historical data is unspecified
|
||||||
func (self *syncer) syncUnsyncedKeys() {
|
func (s *syncer) syncUnsyncedKeys() {
|
||||||
// send out new
|
// send out new
|
||||||
var unsynced []*syncRequest
|
var unsynced []*syncRequest
|
||||||
var more, justSynced bool
|
var more, justSynced bool
|
||||||
|
|
@ -419,12 +419,12 @@ func (self *syncer) syncUnsyncedKeys() {
|
||||||
var history chan interface{}
|
var history chan interface{}
|
||||||
|
|
||||||
priority := High
|
priority := High
|
||||||
keys := self.keys[priority]
|
keys := s.keys[priority]
|
||||||
var newUnsyncedKeys, deliveryRequest chan bool
|
var newUnsyncedKeys, deliveryRequest chan bool
|
||||||
keyCounts := make([]int, priorities)
|
keyCounts := make([]int, priorities)
|
||||||
histPrior := self.SyncPriorities[HistoryReq]
|
histPrior := s.SyncPriorities[HistoryReq]
|
||||||
syncStates := self.syncStates
|
syncStates := s.syncStates
|
||||||
state := self.state
|
state := s.state
|
||||||
|
|
||||||
LOOP:
|
LOOP:
|
||||||
for {
|
for {
|
||||||
|
|
@ -440,15 +440,15 @@ LOOP:
|
||||||
PRIORITIES:
|
PRIORITIES:
|
||||||
for priority = High; priority >= 0; priority-- {
|
for priority = High; priority >= 0; priority-- {
|
||||||
// the first priority channel that is non-empty will be assigned to keys
|
// the first priority channel that is non-empty will be assigned to keys
|
||||||
if len(self.keys[priority]) > 0 {
|
if len(s.keys[priority]) > 0 {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", self.key.Log(), priority))
|
log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", s.key.Log(), priority))
|
||||||
keys = self.keys[priority]
|
keys = s.keys[priority]
|
||||||
break PRIORITIES
|
break PRIORITIES
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("syncer[%v/%v]: queue: [%v, %v, %v]", self.key.Log(), priority, len(self.keys[High]), len(self.keys[Medium]), len(self.keys[Low])))
|
log.Trace(fmt.Sprintf("syncer[%v/%v]: queue: [%v, %v, %v]", s.key.Log(), priority, len(s.keys[High]), len(s.keys[Medium]), len(s.keys[Low])))
|
||||||
// if the input queue is empty on this level, resort to history if there is any
|
// if the input queue is empty on this level, resort to history if there is any
|
||||||
if uint(priority) == histPrior && history != nil {
|
if uint(priority) == histPrior && history != nil {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", self.key.Log(), self.key))
|
log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", s.key.Log(), s.key))
|
||||||
keys = history
|
keys = history
|
||||||
break PRIORITIES
|
break PRIORITIES
|
||||||
}
|
}
|
||||||
|
|
@ -458,8 +458,8 @@ LOOP:
|
||||||
// if peer ready to receive but nothing to send
|
// if peer ready to receive but nothing to send
|
||||||
if keys == nil && deliveryRequest == nil {
|
if keys == nil && deliveryRequest == nil {
|
||||||
// if no items left and switch to waiting mode
|
// if no items left and switch to waiting mode
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", s.key.Log()))
|
||||||
newUnsyncedKeys = self.newUnsyncedKeys
|
newUnsyncedKeys = s.newUnsyncedKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
// send msg iff
|
// send msg iff
|
||||||
|
|
@ -470,48 +470,48 @@ LOOP:
|
||||||
if deliveryRequest == nil &&
|
if deliveryRequest == nil &&
|
||||||
(justSynced ||
|
(justSynced ||
|
||||||
len(unsynced) > 0 && keys == nil ||
|
len(unsynced) > 0 && keys == nil ||
|
||||||
len(unsynced) == int(self.SyncBatchSize)) {
|
len(unsynced) == int(s.SyncBatchSize)) {
|
||||||
justSynced = false
|
justSynced = false
|
||||||
// listen to requests
|
// listen to requests
|
||||||
deliveryRequest = self.deliveryRequest
|
deliveryRequest = s.deliveryRequest
|
||||||
newUnsyncedKeys = nil // not care about data until next req comes in
|
newUnsyncedKeys = nil // not care about data until next req comes in
|
||||||
// set sync to current counter
|
// set sync to current counter
|
||||||
// (all nonhistorical outgoing traffic sheduled and persisted
|
// (all nonhistorical outgoing traffic sheduled and persisted
|
||||||
state.LastSeenAt = self.dbAccess.counter()
|
state.LastSeenAt = s.dbAccess.counter()
|
||||||
state.Latest = storage.ZeroKey
|
state.Latest = storage.ZeroKey
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: sending %v", self.key.Log(), unsynced))
|
log.Trace(fmt.Sprintf("syncer[%v]: sending %v", s.key.Log(), unsynced))
|
||||||
// send the unsynced keys
|
// send the unsynced keys
|
||||||
stateCopy := *state
|
stateCopy := *state
|
||||||
err := self.unsyncedKeys(unsynced, &stateCopy)
|
err := s.unsyncedKeys(unsynced, &stateCopy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", self.key.Log(), err))
|
log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", s.key.Log(), err))
|
||||||
}
|
}
|
||||||
self.state = state
|
s.state = state
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", self.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy))
|
log.Debug(fmt.Sprintf("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", s.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy))
|
||||||
unsynced = nil
|
unsynced = nil
|
||||||
keys = nil
|
keys = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// process item and add it to the batch
|
// process item and add it to the batch
|
||||||
select {
|
select {
|
||||||
case <-self.quit:
|
case <-s.quit:
|
||||||
break LOOP
|
break LOOP
|
||||||
case req, more = <-keys:
|
case req, more = <-keys:
|
||||||
if keys == history && !more {
|
if keys == history && !more {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", s.key.Log()))
|
||||||
// history channel is closed, waiting for new state (called from sync())
|
// history channel is closed, waiting for new state (called from sync())
|
||||||
syncStates = self.syncStates
|
syncStates = s.syncStates
|
||||||
state.Synced = true // this signals that the current segment is complete
|
state.Synced = true // this signals that the current segment is complete
|
||||||
select {
|
select {
|
||||||
case state.synced <- false:
|
case state.synced <- false:
|
||||||
case <-self.quit:
|
case <-s.quit:
|
||||||
break LOOP
|
break LOOP
|
||||||
}
|
}
|
||||||
justSynced = true
|
justSynced = true
|
||||||
history = nil
|
history = nil
|
||||||
}
|
}
|
||||||
case <-deliveryRequest:
|
case <-deliveryRequest:
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", s.key.Log()))
|
||||||
|
|
||||||
// this 1 cap channel can wake up the loop
|
// this 1 cap channel can wake up the loop
|
||||||
// signaling that peer is ready to receive unsynced Keys
|
// signaling that peer is ready to receive unsynced Keys
|
||||||
|
|
@ -519,23 +519,23 @@ LOOP:
|
||||||
deliveryRequest = nil
|
deliveryRequest = nil
|
||||||
|
|
||||||
case <-newUnsyncedKeys:
|
case <-newUnsyncedKeys:
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", s.key.Log()))
|
||||||
// this 1 cap channel can wake up the loop
|
// this 1 cap channel can wake up the loop
|
||||||
// signals that data is available to send if peer is ready to receive
|
// signals that data is available to send if peer is ready to receive
|
||||||
newUnsyncedKeys = nil
|
newUnsyncedKeys = nil
|
||||||
keys = self.keys[High]
|
keys = s.keys[High]
|
||||||
|
|
||||||
case state, more = <-syncStates:
|
case state, more = <-syncStates:
|
||||||
// this resets the state
|
// this resets the state
|
||||||
if !more {
|
if !more {
|
||||||
state = self.state
|
state = s.state
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", self.key.Log(), priority, state))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", s.key.Log(), priority, state))
|
||||||
state.Synced = true
|
state.Synced = true
|
||||||
syncStates = nil
|
syncStates = nil
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", self.key.Log(), priority, state, histPrior))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", s.key.Log(), priority, state, histPrior))
|
||||||
state.Synced = false
|
state.Synced = false
|
||||||
history = self.syncHistory(state)
|
history = s.syncHistory(state)
|
||||||
// only one history at a time, only allow another one once the
|
// only one history at a time, only allow another one once the
|
||||||
// history channel is closed
|
// history channel is closed
|
||||||
syncStates = nil
|
syncStates = nil
|
||||||
|
|
@ -545,19 +545,19 @@ LOOP:
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", self.key.Log(), priority, req))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", s.key.Log(), priority, req))
|
||||||
keyCounts[priority]++
|
keyCounts[priority]++
|
||||||
keyCount++
|
keyCount++
|
||||||
if keys == history {
|
if keys == history {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", s.key.Log(), priority, req, state.Synced))
|
||||||
historyCnt++
|
historyCnt++
|
||||||
}
|
}
|
||||||
if sreq, err := self.newSyncRequest(req, priority); err == nil {
|
if sreq, err := s.newSyncRequest(req, priority); err == nil {
|
||||||
// extract key from req
|
// extract key from req
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", s.key.Log(), priority, req, state.Synced))
|
||||||
unsynced = append(unsynced, sreq)
|
unsynced = append(unsynced, sreq)
|
||||||
} else {
|
} else {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", self.key.Log(), priority, req, err))
|
log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", s.key.Log(), priority, req, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -566,7 +566,7 @@ LOOP:
|
||||||
// delivery loop
|
// delivery loop
|
||||||
// takes into account priority, send store Requests with chunk (delivery)
|
// takes into account priority, send store Requests with chunk (delivery)
|
||||||
// idle blocking if no new deliveries in any of the queues
|
// idle blocking if no new deliveries in any of the queues
|
||||||
func (self *syncer) syncDeliveries() {
|
func (s *syncer) syncDeliveries() {
|
||||||
var req *storeRequestMsgData
|
var req *storeRequestMsgData
|
||||||
p := High
|
p := High
|
||||||
var deliveries chan *storeRequestMsgData
|
var deliveries chan *storeRequestMsgData
|
||||||
|
|
@ -577,7 +577,7 @@ func (self *syncer) syncDeliveries() {
|
||||||
var total, success uint
|
var total, success uint
|
||||||
|
|
||||||
for {
|
for {
|
||||||
deliveries = self.deliveries[p]
|
deliveries = s.deliveries[p]
|
||||||
select {
|
select {
|
||||||
case req = <-deliveries:
|
case req = <-deliveries:
|
||||||
n[p]++
|
n[p]++
|
||||||
|
|
@ -586,13 +586,13 @@ func (self *syncer) syncDeliveries() {
|
||||||
if p == Low {
|
if p == Low {
|
||||||
// blocking, depletion on all channels, no preference for priority
|
// blocking, depletion on all channels, no preference for priority
|
||||||
select {
|
select {
|
||||||
case req = <-self.deliveries[High]:
|
case req = <-s.deliveries[High]:
|
||||||
n[High]++
|
n[High]++
|
||||||
case req = <-self.deliveries[Medium]:
|
case req = <-s.deliveries[Medium]:
|
||||||
n[Medium]++
|
n[Medium]++
|
||||||
case req = <-self.deliveries[Low]:
|
case req = <-s.deliveries[Low]:
|
||||||
n[Low]++
|
n[Low]++
|
||||||
case <-self.quit:
|
case <-s.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p = High
|
p = High
|
||||||
|
|
@ -602,20 +602,20 @@ func (self *syncer) syncDeliveries() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total++
|
total++
|
||||||
msg, err = self.newStoreRequestMsgData(req)
|
msg, err = s.newStoreRequestMsgData(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", self.key.Log(), req, err))
|
log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", s.key.Log(), req, err))
|
||||||
} else {
|
} else {
|
||||||
err = self.store(msg)
|
err = s.store(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", self.key.Log(), req, err))
|
log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", s.key.Log(), req, err))
|
||||||
} else {
|
} else {
|
||||||
success++
|
success++
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", self.key.Log(), req))
|
log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", s.key.Log(), req))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if total%self.SyncBatchSize == 0 {
|
if total%s.SyncBatchSize == 0 {
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", self.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low]))
|
log.Debug(fmt.Sprintf("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", s.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,28 +635,28 @@ func (self *syncer) syncDeliveries() {
|
||||||
|
|
||||||
If sync mode is off then, requests are directly sent to deliveries
|
If sync mode is off then, requests are directly sent to deliveries
|
||||||
*/
|
*/
|
||||||
func (self *syncer) addRequest(req interface{}, ty int) {
|
func (s *syncer) addRequest(req interface{}, ty int) {
|
||||||
// retrieve priority for request type name int8
|
// retrieve priority for request type name int8
|
||||||
|
|
||||||
priority := self.SyncPriorities[ty]
|
priority := s.SyncPriorities[ty]
|
||||||
// sync mode for this type ON
|
// sync mode for this type ON
|
||||||
if self.syncF() || ty == DeliverReq {
|
if s.syncF() || ty == DeliverReq {
|
||||||
if self.SyncModes[ty] {
|
if s.SyncModes[ty] {
|
||||||
self.addKey(req, priority, self.quit)
|
s.addKey(req, priority, s.quit)
|
||||||
} else {
|
} else {
|
||||||
self.addDelivery(req, priority, self.quit)
|
s.addDelivery(req, priority, s.quit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// addKey queues sync request for sync confirmation with given priority
|
// addKey queues sync request for sync confirmation with given priority
|
||||||
// ie the key will go out in an unsyncedKeys message
|
// ie the key will go out in an unsyncedKeys message
|
||||||
func (self *syncer) addKey(req interface{}, priority uint, quit chan bool) bool {
|
func (s *syncer) addKey(req interface{}, priority uint, quit chan bool) bool {
|
||||||
select {
|
select {
|
||||||
case self.keys[priority] <- req:
|
case s.keys[priority] <- req:
|
||||||
// this wakes up the unsynced keys loop if idle
|
// this wakes up the unsynced keys loop if idle
|
||||||
select {
|
select {
|
||||||
case self.newUnsyncedKeys <- true:
|
case s.newUnsyncedKeys <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -668,9 +668,9 @@ func (self *syncer) addKey(req interface{}, priority uint, quit chan bool) bool
|
||||||
// addDelivery queues delivery request for with given priority
|
// addDelivery queues delivery request for with given priority
|
||||||
// ie the chunk will be delivered ASAP mod priority queueing handled by syncdb
|
// ie the chunk will be delivered ASAP mod priority queueing handled by syncdb
|
||||||
// requests are persisted across sessions for correct sync
|
// requests are persisted across sessions for correct sync
|
||||||
func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool) bool {
|
func (s *syncer) addDelivery(req interface{}, priority uint, quit chan bool) bool {
|
||||||
select {
|
select {
|
||||||
case self.queues[priority].buffer <- req:
|
case s.queues[priority].buffer <- req:
|
||||||
return true
|
return true
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return false
|
return false
|
||||||
|
|
@ -679,14 +679,14 @@ func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool)
|
||||||
|
|
||||||
// doDelivery delivers the chunk for the request with given priority
|
// doDelivery delivers the chunk for the request with given priority
|
||||||
// without queuing
|
// without queuing
|
||||||
func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool {
|
func (s *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool {
|
||||||
msgdata, err := self.newStoreRequestMsgData(req)
|
msgdata, err := s.newStoreRequestMsgData(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err))
|
log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case self.deliveries[priority] <- msgdata:
|
case s.deliveries[priority] <- msgdata:
|
||||||
return true
|
return true
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return false
|
return false
|
||||||
|
|
@ -695,9 +695,9 @@ func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) b
|
||||||
|
|
||||||
// returns the delivery function for given priority
|
// returns the delivery function for given priority
|
||||||
// passed on to syncDb
|
// passed on to syncDb
|
||||||
func (self *syncer) deliver(priority uint) func(req interface{}, quit chan bool) bool {
|
func (s *syncer) deliver(priority uint) func(req interface{}, quit chan bool) bool {
|
||||||
return func(req interface{}, quit chan bool) bool {
|
return func(req interface{}, quit chan bool) bool {
|
||||||
return self.doDelivery(req, priority, quit)
|
return s.doDelivery(req, priority, quit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -705,17 +705,17 @@ func (self *syncer) deliver(priority uint) func(req interface{}, quit chan bool)
|
||||||
// depending on sync mode settings for BacklogReq,
|
// depending on sync mode settings for BacklogReq,
|
||||||
// re play of request db backlog sends items via confirmation
|
// re play of request db backlog sends items via confirmation
|
||||||
// or directly delivers
|
// or directly delivers
|
||||||
func (self *syncer) replay() func(req interface{}, quit chan bool) bool {
|
func (s *syncer) replay() func(req interface{}, quit chan bool) bool {
|
||||||
sync := self.SyncModes[BacklogReq]
|
sync := s.SyncModes[BacklogReq]
|
||||||
priority := self.SyncPriorities[BacklogReq]
|
priority := s.SyncPriorities[BacklogReq]
|
||||||
// sync mode for this type ON
|
// sync mode for this type ON
|
||||||
if sync {
|
if sync {
|
||||||
return func(req interface{}, quit chan bool) bool {
|
return func(req interface{}, quit chan bool) bool {
|
||||||
return self.addKey(req, priority, quit)
|
return s.addKey(req, priority, quit)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return func(req interface{}, quit chan bool) bool {
|
return func(req interface{}, quit chan bool) bool {
|
||||||
return self.doDelivery(req, priority, quit)
|
return s.doDelivery(req, priority, quit)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -723,7 +723,7 @@ func (self *syncer) replay() func(req interface{}, quit chan bool) bool {
|
||||||
|
|
||||||
// given a request, extends it to a full storeRequestMsgData
|
// given a request, extends it to a full storeRequestMsgData
|
||||||
// polimorphic: see addRequest for the types accepted
|
// polimorphic: see addRequest for the types accepted
|
||||||
func (self *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgData, error) {
|
func (s *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgData, error) {
|
||||||
|
|
||||||
key, id, chunk, sreq, err := parseRequest(req)
|
key, id, chunk, sreq, err := parseRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -733,7 +733,7 @@ func (self *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgDat
|
||||||
if sreq == nil {
|
if sreq == nil {
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
var err error
|
var err error
|
||||||
chunk, err = self.dbAccess.get(key)
|
chunk, err = s.dbAccess.get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,10 @@ func NewDefaultSwapParams() *SwapParams {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) {
|
func (params *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) {
|
||||||
pubkey := &prvkey.PublicKey
|
pubkey := &prvkey.PublicKey
|
||||||
|
|
||||||
self.PayProfile = &PayProfile{
|
params.PayProfile = &PayProfile{
|
||||||
PublicKey: common.ToHex(crypto.FromECDSAPub(pubkey)),
|
PublicKey: common.ToHex(crypto.FromECDSAPub(pubkey)),
|
||||||
Contract: contract,
|
Contract: contract,
|
||||||
Beneficiary: crypto.PubkeyToAddress(*pubkey),
|
Beneficiary: crypto.PubkeyToAddress(*pubkey),
|
||||||
|
|
@ -126,7 +126,7 @@ func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey)
|
||||||
// n < 0 called when receiving chunks = receiving delivery responses
|
// n < 0 called when receiving chunks = receiving delivery responses
|
||||||
// OR receiving cheques.
|
// OR receiving cheques.
|
||||||
|
|
||||||
func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend, proto swap.Protocol) (self *swap.Swap, err error) {
|
func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend, proto swap.Protocol) (s *swap.Swap, err error) {
|
||||||
var (
|
var (
|
||||||
ctx = context.TODO()
|
ctx = context.TODO()
|
||||||
ok bool
|
ok bool
|
||||||
|
|
@ -162,19 +162,19 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
||||||
Buys: out != nil,
|
Buys: out != nil,
|
||||||
Sells: in != nil,
|
Sells: in != nil,
|
||||||
}
|
}
|
||||||
self, err = swap.New(local.Params, pm, proto)
|
s, err = swap.New(local.Params, pm, proto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// remote profile given (first) in handshake
|
// remote profile given (first) in handshake
|
||||||
self.SetRemote(remote.Profile)
|
s.SetRemote(remote.Profile)
|
||||||
var buy, sell string
|
var buy, sell string
|
||||||
if self.Buys {
|
if s.Buys {
|
||||||
buy = "purchase from peer enabled at " + remote.SellAt.String() + " wei/chunk"
|
buy = "purchase from peer enabled at " + remote.SellAt.String() + " wei/chunk"
|
||||||
} else {
|
} else {
|
||||||
buy = "purchase from peer disabled"
|
buy = "purchase from peer disabled"
|
||||||
}
|
}
|
||||||
if self.Sells {
|
if s.Sells {
|
||||||
sell = "selling to peer enabled at " + local.SellAt.String() + " wei/chunk"
|
sell = "selling to peer enabled at " + local.SellAt.String() + " wei/chunk"
|
||||||
} else {
|
} else {
|
||||||
sell = "selling to peer disabled"
|
sell = "selling to peer disabled"
|
||||||
|
|
@ -184,44 +184,44 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwapParams) Chequebook() *chequebook.Chequebook {
|
func (params *SwapParams) Chequebook() *chequebook.Chequebook {
|
||||||
defer self.lock.Unlock()
|
defer params.lock.Unlock()
|
||||||
self.lock.Lock()
|
params.lock.Lock()
|
||||||
return self.chbook
|
return params.chbook
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwapParams) PrivateKey() *ecdsa.PrivateKey {
|
func (params *SwapParams) PrivateKey() *ecdsa.PrivateKey {
|
||||||
return self.privateKey
|
return params.privateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (self *SwapParams) PublicKey() *ecdsa.PublicKey {
|
// func (params *SwapParams) PublicKey() *ecdsa.PublicKey {
|
||||||
// return self.publicKey
|
// return params.publicKey
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (self *SwapParams) SetKey(prvkey *ecdsa.PrivateKey) {
|
func (params *SwapParams) SetKey(prvkey *ecdsa.PrivateKey) {
|
||||||
self.privateKey = prvkey
|
params.privateKey = prvkey
|
||||||
self.publicKey = &prvkey.PublicKey
|
params.publicKey = &prvkey.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// setChequebook(path, backend) wraps the
|
// setChequebook(path, backend) wraps the
|
||||||
// chequebook initialiser and sets up autoDeposit to cover spending.
|
// chequebook initialiser and sets up autoDeposit to cover spending.
|
||||||
func (self *SwapParams) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
func (params *SwapParams) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
||||||
self.lock.Lock()
|
params.lock.Lock()
|
||||||
contract := self.Contract
|
contract := params.Contract
|
||||||
self.lock.Unlock()
|
params.lock.Unlock()
|
||||||
|
|
||||||
valid, err := chequebook.ValidateCode(ctx, backend, contract)
|
valid, err := chequebook.ValidateCode(ctx, backend, contract)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if valid {
|
} else if valid {
|
||||||
return self.newChequebookFromContract(path, backend)
|
return params.newChequebookFromContract(path, backend)
|
||||||
}
|
}
|
||||||
return self.deployChequebook(ctx, backend, path)
|
return params.deployChequebook(ctx, backend, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
func (params *SwapParams) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
||||||
opts := bind.NewKeyedTransactor(self.privateKey)
|
opts := bind.NewKeyedTransactor(params.privateKey)
|
||||||
opts.Value = self.AutoDepositBuffer
|
opts.Value = params.AutoDepositBuffer
|
||||||
opts.Context = ctx
|
opts.Context = ctx
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex()))
|
log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex()))
|
||||||
|
|
@ -233,10 +233,10 @@ func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook
|
||||||
log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex()))
|
log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex()))
|
||||||
|
|
||||||
// need to save config at this point
|
// need to save config at this point
|
||||||
self.lock.Lock()
|
params.lock.Lock()
|
||||||
self.Contract = contract
|
params.Contract = contract
|
||||||
err = self.newChequebookFromContract(path, backend)
|
err = params.newChequebookFromContract(path, backend)
|
||||||
self.lock.Unlock()
|
params.lock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err))
|
log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err))
|
||||||
}
|
}
|
||||||
|
|
@ -265,26 +265,26 @@ func deployChequebookLoop(opts *bind.TransactOpts, backend chequebook.Backend) (
|
||||||
|
|
||||||
// initialise the chequebook from a persisted json file or create a new one
|
// initialise the chequebook from a persisted json file or create a new one
|
||||||
// caller holds the lock
|
// caller holds the lock
|
||||||
func (self *SwapParams) newChequebookFromContract(path string, backend chequebook.Backend) error {
|
func (params *SwapParams) newChequebookFromContract(path string, backend chequebook.Backend) error {
|
||||||
hexkey := common.Bytes2Hex(self.Contract.Bytes())
|
hexkey := common.Bytes2Hex(params.Contract.Bytes())
|
||||||
err := os.MkdirAll(filepath.Join(path, "chequebooks"), os.ModePerm)
|
err := os.MkdirAll(filepath.Join(path, "chequebooks"), os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create directory for chequebooks: %v", err)
|
return fmt.Errorf("unable to create directory for chequebooks: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chbookpath := filepath.Join(path, "chequebooks", hexkey+".json")
|
chbookpath := filepath.Join(path, "chequebooks", hexkey+".json")
|
||||||
self.chbook, err = chequebook.LoadChequebook(chbookpath, self.privateKey, backend, true)
|
params.chbook, err = chequebook.LoadChequebook(chbookpath, params.privateKey, backend, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.chbook, err = chequebook.NewChequebook(chbookpath, self.Contract, self.privateKey, backend)
|
params.chbook, err = chequebook.NewChequebook(chbookpath, params.Contract, params.privateKey, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err))
|
log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", params.owner.Hex(), err))
|
||||||
return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err)
|
return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", params.owner.Hex(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chbook.AutoDeposit(self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer)
|
params.chbook.AutoDeposit(params.AutoDepositInterval, params.AutoDepositThreshold, params.AutoDepositBuffer)
|
||||||
log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(self.publicKey)).Hex()[:8], self.Contract.Hex()[:8], self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer))
|
log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(params.publicKey)).Hex()[:8], params.Contract.Hex()[:8], params.AutoDepositInterval, params.AutoDepositThreshold, params.AutoDepositBuffer))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,153 +100,153 @@ type Payment struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap constructor
|
// swap constructor
|
||||||
func New(local *Params, pm Payment, proto Protocol) (self *Swap, err error) {
|
func New(local *Params, pm Payment, proto Protocol) (s *Swap, err error) {
|
||||||
|
|
||||||
self = &Swap{
|
s = &Swap{
|
||||||
local: local,
|
local: local,
|
||||||
Payment: pm,
|
Payment: pm,
|
||||||
proto: proto,
|
proto: proto,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.SetParams(local)
|
s.SetParams(local)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// entry point for setting remote swap profile (e.g from handshake or other message)
|
// entry point for setting remote swap profile (e.g from handshake or other message)
|
||||||
func (self *Swap) SetRemote(remote *Profile) {
|
func (s *Swap) SetRemote(remote *Profile) {
|
||||||
defer self.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
self.lock.Lock()
|
s.lock.Lock()
|
||||||
|
|
||||||
self.remote = remote
|
s.remote = remote
|
||||||
if self.Sells && (remote.BuyAt.Sign() <= 0 || self.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(self.local.SellAt) < 0) {
|
if s.Sells && (remote.BuyAt.Sign() <= 0 || s.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(s.local.SellAt) < 0) {
|
||||||
self.Out.Stop()
|
s.Out.Stop()
|
||||||
self.Sells = false
|
s.Sells = false
|
||||||
}
|
}
|
||||||
if self.Buys && (remote.SellAt.Sign() <= 0 || self.local.BuyAt.Sign() <= 0 || self.local.BuyAt.Cmp(self.remote.SellAt) < 0) {
|
if s.Buys && (remote.SellAt.Sign() <= 0 || s.local.BuyAt.Sign() <= 0 || s.local.BuyAt.Cmp(s.remote.SellAt) < 0) {
|
||||||
self.In.Stop()
|
s.In.Stop()
|
||||||
self.Buys = false
|
s.Buys = false
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", self.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt))
|
log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", s.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// to set strategy dynamically
|
// to set strategy dynamically
|
||||||
func (self *Swap) SetParams(local *Params) {
|
func (s *Swap) SetParams(local *Params) {
|
||||||
defer self.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
self.lock.Lock()
|
s.lock.Lock()
|
||||||
self.local = local
|
s.local = local
|
||||||
self.setParams(local)
|
s.setParams(local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// caller holds the lock
|
// caller holds the lock
|
||||||
|
|
||||||
func (self *Swap) setParams(local *Params) {
|
func (s *Swap) setParams(local *Params) {
|
||||||
|
|
||||||
if self.Sells {
|
if s.Sells {
|
||||||
self.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold)
|
s.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold)
|
||||||
log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", self.proto, local.AutoCashInterval, local.AutoCashThreshold))
|
log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", s.proto, local.AutoCashInterval, local.AutoCashThreshold))
|
||||||
} else {
|
} else {
|
||||||
log.Info(fmt.Sprintf("<%v> autocash off (not selling)", self.proto))
|
log.Info(fmt.Sprintf("<%v> autocash off (not selling)", s.proto))
|
||||||
}
|
}
|
||||||
if self.Buys {
|
if s.Buys {
|
||||||
self.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)
|
s.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)
|
||||||
log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", self.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer))
|
log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", s.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer))
|
||||||
} else {
|
} else {
|
||||||
log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", self.proto))
|
log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", s.proto))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add(n)
|
// Add(n)
|
||||||
// n > 0 called when promised/provided n units of service
|
// n > 0 called when promised/provided n units of service
|
||||||
// n < 0 called when used/requested n units of service
|
// n < 0 called when used/requested n units of service
|
||||||
func (self *Swap) Add(n int) error {
|
func (s *Swap) Add(n int) error {
|
||||||
defer self.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
self.lock.Lock()
|
s.lock.Lock()
|
||||||
self.balance += n
|
s.balance += n
|
||||||
if !self.Sells && self.balance > 0 {
|
if !s.Sells && s.balance > 0 {
|
||||||
log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance))
|
log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", s.proto, s.balance))
|
||||||
self.proto.Drop()
|
s.proto.Drop()
|
||||||
return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance)
|
return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", s.proto, s.balance)
|
||||||
}
|
}
|
||||||
if !self.Buys && self.balance < 0 {
|
if !s.Buys && s.balance < 0 {
|
||||||
log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", self.proto, self.balance))
|
log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", s.proto, s.balance))
|
||||||
return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", self.proto, self.balance)
|
return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", s.proto, s.balance)
|
||||||
}
|
}
|
||||||
if self.balance >= int(self.local.DropAt) {
|
if s.balance >= int(s.local.DropAt) {
|
||||||
log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt))
|
log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", s.proto, s.balance, s.local.DropAt))
|
||||||
self.proto.Drop()
|
s.proto.Drop()
|
||||||
return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt)
|
return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", s.proto, s.balance, s.local.DropAt)
|
||||||
} else if self.balance <= -int(self.remote.PayAt) {
|
} else if s.balance <= -int(s.remote.PayAt) {
|
||||||
self.send()
|
s.send()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swap) Balance() int {
|
func (s *Swap) Balance() int {
|
||||||
defer self.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
self.lock.Lock()
|
s.lock.Lock()
|
||||||
return self.balance
|
return s.balance
|
||||||
}
|
}
|
||||||
|
|
||||||
// send(units) is called when payment is due
|
// send(units) is called when payment is due
|
||||||
// In case of insolvency no promise is issued and sent, safe against fraud
|
// In case of insolvency no promise is issued and sent, safe against fraud
|
||||||
// No return value: no error = payment is opportunistic = hang in till dropped
|
// No return value: no error = payment is opportunistic = hang in till dropped
|
||||||
func (self *Swap) send() {
|
func (s *Swap) send() {
|
||||||
if self.local.BuyAt != nil && self.balance < 0 {
|
if s.local.BuyAt != nil && s.balance < 0 {
|
||||||
amount := big.NewInt(int64(-self.balance))
|
amount := big.NewInt(int64(-s.balance))
|
||||||
amount.Mul(amount, self.remote.SellAt)
|
amount.Mul(amount, s.remote.SellAt)
|
||||||
promise, err := self.Out.Issue(amount)
|
promise, err := s.Out.Issue(amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", self.proto, amount, self.Out, err))
|
log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", s.proto, amount, s.Out, err))
|
||||||
} else {
|
} else {
|
||||||
log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", self.proto, amount, self.Out))
|
log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", s.proto, amount, s.Out))
|
||||||
self.proto.Pay(-self.balance, promise)
|
s.proto.Pay(-s.balance, promise)
|
||||||
self.balance = 0
|
s.balance = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// receive(units, promise) is called by the protocol when a payment msg is received
|
// receive(units, promise) is called by the protocol when a payment msg is received
|
||||||
// returns error if promise is invalid.
|
// returns error if promise is invalid.
|
||||||
func (self *Swap) Receive(units int, promise Promise) error {
|
func (s *Swap) Receive(units int, promise Promise) error {
|
||||||
if units <= 0 {
|
if units <= 0 {
|
||||||
return fmt.Errorf("invalid units: %v <= 0", units)
|
return fmt.Errorf("invalid units: %v <= 0", units)
|
||||||
}
|
}
|
||||||
|
|
||||||
price := new(big.Int).SetInt64(int64(units))
|
price := new(big.Int).SetInt64(int64(units))
|
||||||
price.Mul(price, self.local.SellAt)
|
price.Mul(price, s.local.SellAt)
|
||||||
|
|
||||||
amount, err := self.In.Receive(promise)
|
amount, err := s.In.Receive(promise)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("invalid promise: %v", err)
|
err = fmt.Errorf("invalid promise: %v", err)
|
||||||
} else if price.Cmp(amount) != 0 {
|
} else if price.Cmp(amount) != 0 {
|
||||||
// verify amount = units * unit sale price
|
// verify amount = units * unit sale price
|
||||||
return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, self.local.SellAt, amount)
|
return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, s.local.SellAt, amount)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, err))
|
log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", s.proto, amount, s.In, err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// credit remote peer with units
|
// credit remote peer with units
|
||||||
self.Add(-units)
|
s.Add(-units)
|
||||||
log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, promise))
|
log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", s.proto, amount, s.In, promise))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop() causes autocash loop to terminate.
|
// stop() causes autocash loop to terminate.
|
||||||
// Called after protocol handle loop terminates.
|
// Called after protocol handle loop terminates.
|
||||||
func (self *Swap) Stop() {
|
func (s *Swap) Stop() {
|
||||||
defer self.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
self.lock.Lock()
|
s.lock.Lock()
|
||||||
if self.Buys {
|
if s.Buys {
|
||||||
self.Out.Stop()
|
s.Out.Stop()
|
||||||
}
|
}
|
||||||
if self.Sells {
|
if s.Sells {
|
||||||
self.In.Stop()
|
s.In.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,20 +34,20 @@ type testPromise struct {
|
||||||
amount *big.Int
|
amount *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testInPayment) Receive(promise Promise) (*big.Int, error) {
|
func (t *testInPayment) Receive(promise Promise) (*big.Int, error) {
|
||||||
p := promise.(*testPromise)
|
p := promise.(*testPromise)
|
||||||
self.received = append(self.received, p)
|
t.received = append(t.received, p)
|
||||||
return p.amount, nil
|
return p.amount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testInPayment) AutoCash(interval time.Duration, limit *big.Int) {
|
func (t *testInPayment) AutoCash(interval time.Duration, limit *big.Int) {
|
||||||
self.autocashInterval = interval
|
t.autocashInterval = interval
|
||||||
self.autocashLimit = limit
|
t.autocashLimit = limit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testInPayment) Cash() (string, error) { return "", nil }
|
func (t *testInPayment) Cash() (string, error) { return "", nil }
|
||||||
|
|
||||||
func (self *testInPayment) Stop() {}
|
func (t *testInPayment) Stop() {}
|
||||||
|
|
||||||
type testOutPayment struct {
|
type testOutPayment struct {
|
||||||
deposits []*big.Int
|
deposits []*big.Int
|
||||||
|
|
@ -56,22 +56,22 @@ type testOutPayment struct {
|
||||||
autodepositBuffer *big.Int
|
autodepositBuffer *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) {
|
func (t *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) {
|
||||||
return &testPromise{amount}, nil
|
return &testPromise{amount}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) Deposit(amount *big.Int) (string, error) {
|
func (t *testOutPayment) Deposit(amount *big.Int) (string, error) {
|
||||||
self.deposits = append(self.deposits, amount)
|
t.deposits = append(t.deposits, amount)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
func (t *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
||||||
self.autodepositInterval = interval
|
t.autodepositInterval = interval
|
||||||
self.autodepositThreshold = threshold
|
t.autodepositThreshold = threshold
|
||||||
self.autodepositBuffer = buffer
|
t.autodepositBuffer = buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) Stop() {}
|
func (t *testOutPayment) Stop() {}
|
||||||
|
|
||||||
type testProtocol struct {
|
type testProtocol struct {
|
||||||
drop bool
|
drop bool
|
||||||
|
|
@ -79,18 +79,18 @@ type testProtocol struct {
|
||||||
promises []*testPromise
|
promises []*testPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testProtocol) Drop() {
|
func (t *testProtocol) Drop() {
|
||||||
self.drop = true
|
t.drop = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testProtocol) String() string {
|
func (t *testProtocol) String() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testProtocol) Pay(amount int, promise Promise) {
|
func (t *testProtocol) Pay(amount int, promise Promise) {
|
||||||
p := promise.(*testPromise)
|
p := promise.(*testPromise)
|
||||||
self.promises = append(self.promises, p)
|
t.promises = append(t.promises, p)
|
||||||
self.amounts = append(self.amounts, amount)
|
t.amounts = append(t.amounts, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSwap(t *testing.T) {
|
func TestSwap(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -74,30 +74,30 @@ type TreeChunker struct {
|
||||||
branches int64
|
branches int64
|
||||||
hashFunc SwarmHasher
|
hashFunc SwarmHasher
|
||||||
// calculated
|
// calculated
|
||||||
hashSize int64 // self.hashFunc.New().Size()
|
hashSize int64 // hashFunc.New().Size()
|
||||||
chunkSize int64 // hashSize*branches
|
chunkSize int64 // hashSize*branches
|
||||||
workerCount int64 // the number of worker routines used
|
workerCount int64 // the number of worker routines used
|
||||||
workerLock sync.RWMutex // lock for the worker count
|
workerLock sync.RWMutex // lock for the worker count
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTreeChunker(params *ChunkerParams) (self *TreeChunker) {
|
func NewTreeChunker(params *ChunkerParams) (chunker *TreeChunker) {
|
||||||
self = &TreeChunker{}
|
chunker = &TreeChunker{}
|
||||||
self.hashFunc = MakeHashFunc(params.Hash)
|
chunker.hashFunc = MakeHashFunc(params.Hash)
|
||||||
self.branches = params.Branches
|
chunker.branches = params.Branches
|
||||||
self.hashSize = int64(self.hashFunc().Size())
|
chunker.hashSize = int64(chunker.hashFunc().Size())
|
||||||
self.chunkSize = self.hashSize * self.branches
|
chunker.chunkSize = chunker.hashSize * chunker.branches
|
||||||
self.workerCount = 0
|
chunker.workerCount = 0
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (self *TreeChunker) KeySize() int64 {
|
// func (chunker *TreeChunker) KeySize() int64 {
|
||||||
// return self.hashSize
|
// return chunker.hashSize
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// String() for pretty printing
|
// String() for pretty printing
|
||||||
func (self *Chunk) String() string {
|
func (c *Chunk) String() string {
|
||||||
return fmt.Sprintf("Key: %v TreeSize: %v Chunksize: %v", self.Key.Log(), self.Size, len(self.SData))
|
return fmt.Sprintf("Key: %v TreeSize: %v Chunksize: %v", c.Key.Log(), c.Size, len(c.SData))
|
||||||
}
|
}
|
||||||
|
|
||||||
type hashJob struct {
|
type hashJob struct {
|
||||||
|
|
@ -107,26 +107,26 @@ type hashJob struct {
|
||||||
parentWg *sync.WaitGroup
|
parentWg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) incrementWorkerCount() {
|
func (chunker *TreeChunker) incrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
chunker.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer chunker.workerLock.Unlock()
|
||||||
self.workerCount += 1
|
chunker.workerCount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) getWorkerCount() int64 {
|
func (chunker *TreeChunker) getWorkerCount() int64 {
|
||||||
self.workerLock.RLock()
|
chunker.workerLock.RLock()
|
||||||
defer self.workerLock.RUnlock()
|
defer chunker.workerLock.RUnlock()
|
||||||
return self.workerCount
|
return chunker.workerCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) decrementWorkerCount() {
|
func (chunker *TreeChunker) decrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
chunker.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer chunker.workerLock.Unlock()
|
||||||
self.workerCount -= 1
|
chunker.workerCount -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
func (chunker *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
||||||
if self.chunkSize <= 0 {
|
if chunker.chunkSize <= 0 {
|
||||||
panic("chunker must be initialised")
|
panic("chunker must be initialised")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,23 +140,23 @@ func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, s
|
||||||
wwg.Add(1)
|
wwg.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.incrementWorkerCount()
|
chunker.incrementWorkerCount()
|
||||||
go self.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
go chunker.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
||||||
|
|
||||||
depth := 0
|
depth := 0
|
||||||
treeSize := self.chunkSize
|
treeSize := chunker.chunkSize
|
||||||
|
|
||||||
// takes lowest depth such that chunksize*HashCount^(depth+1) > size
|
// takes lowest depth such that chunksize*HashCount^(depth+1) > size
|
||||||
// power series, will find the order of magnitude of the data size in base hashCount or numbers of levels of branching in the resulting tree.
|
// power series, will find the order of magnitude of the data size in base hashCount or numbers of levels of branching in the resulting tree.
|
||||||
for ; treeSize < size; treeSize *= self.branches {
|
for ; treeSize < size; treeSize *= chunker.branches {
|
||||||
depth++
|
depth++
|
||||||
}
|
}
|
||||||
|
|
||||||
key := make([]byte, self.hashFunc().Size())
|
key := make([]byte, chunker.hashFunc().Size())
|
||||||
// this waitgroup member is released after the root hash is calculated
|
// this waitgroup member is released after the root hash is calculated
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
//launch actual recursive function passing the waitgroups
|
//launch actual recursive function passing the waitgroups
|
||||||
go self.split(depth, treeSize/self.branches, key, data, size, jobC, chunkC, errC, quitC, wg, swg, wwg)
|
go chunker.split(depth, treeSize/chunker.branches, key, data, size, jobC, chunkC, errC, quitC, wg, swg, wwg)
|
||||||
|
|
||||||
// closes internal error channel if all subprocesses in the workgroup finished
|
// closes internal error channel if all subprocesses in the workgroup finished
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -182,12 +182,12 @@ func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, s
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reader, size int64, jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, parentWg, swg, wwg *sync.WaitGroup) {
|
func (chunker *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reader, size int64, jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, parentWg, swg, wwg *sync.WaitGroup) {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
for depth > 0 && size < treeSize {
|
for depth > 0 && size < treeSize {
|
||||||
treeSize /= self.branches
|
treeSize /= chunker.branches
|
||||||
depth--
|
depth--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +214,7 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
// intermediate chunk containing child nodes hashes
|
// intermediate chunk containing child nodes hashes
|
||||||
branchCnt := (size + treeSize - 1) / treeSize
|
branchCnt := (size + treeSize - 1) / treeSize
|
||||||
|
|
||||||
var chunk = make([]byte, branchCnt*self.hashSize+8)
|
var chunk = make([]byte, branchCnt*chunker.hashSize+8)
|
||||||
var pos, i int64
|
var pos, i int64
|
||||||
|
|
||||||
binary.LittleEndian.PutUint64(chunk[0:8], uint64(size))
|
binary.LittleEndian.PutUint64(chunk[0:8], uint64(size))
|
||||||
|
|
@ -229,10 +229,10 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
secSize = treeSize
|
secSize = treeSize
|
||||||
}
|
}
|
||||||
// the hash of that data
|
// the hash of that data
|
||||||
subTreeKey := chunk[8+i*self.hashSize : 8+(i+1)*self.hashSize]
|
subTreeKey := chunk[8+i*chunker.hashSize : 8+(i+1)*chunker.hashSize]
|
||||||
|
|
||||||
childrenWg.Add(1)
|
childrenWg.Add(1)
|
||||||
self.split(depth-1, treeSize/self.branches, subTreeKey, data, secSize, jobC, chunkC, errC, quitC, childrenWg, swg, wwg)
|
chunker.split(depth-1, treeSize/chunker.branches, subTreeKey, data, secSize, jobC, chunkC, errC, quitC, childrenWg, swg, wwg)
|
||||||
|
|
||||||
i++
|
i++
|
||||||
pos += treeSize
|
pos += treeSize
|
||||||
|
|
@ -242,13 +242,13 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
// go func() {
|
// go func() {
|
||||||
childrenWg.Wait()
|
childrenWg.Wait()
|
||||||
|
|
||||||
worker := self.getWorkerCount()
|
worker := chunker.getWorkerCount()
|
||||||
if int64(len(jobC)) > worker && worker < ChunkProcessors {
|
if int64(len(jobC)) > worker && worker < ChunkProcessors {
|
||||||
if wwg != nil {
|
if wwg != nil {
|
||||||
wwg.Add(1)
|
wwg.Add(1)
|
||||||
}
|
}
|
||||||
self.incrementWorkerCount()
|
chunker.incrementWorkerCount()
|
||||||
go self.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
go chunker.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
||||||
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
|
@ -257,10 +257,10 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
func (chunker *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
||||||
defer self.decrementWorkerCount()
|
defer chunker.decrementWorkerCount()
|
||||||
|
|
||||||
hasher := self.hashFunc()
|
hasher := chunker.hashFunc()
|
||||||
if wwg != nil {
|
if wwg != nil {
|
||||||
defer wwg.Done()
|
defer wwg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +272,7 @@ func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// now we got the hashes in the chunk, then hash the chunks
|
// now we got the hashes in the chunk, then hash the chunks
|
||||||
self.hashChunk(hasher, job, chunkC, swg)
|
chunker.hashChunk(hasher, job, chunkC, swg)
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -282,7 +282,7 @@ func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC
|
||||||
// The treeChunkers own Hash hashes together
|
// The treeChunkers own Hash hashes together
|
||||||
// - the size (of the subtree encoded in the Chunk)
|
// - the size (of the subtree encoded in the Chunk)
|
||||||
// - the Chunk, ie. the contents read from the input reader
|
// - the Chunk, ie. the contents read from the input reader
|
||||||
func (self *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
func (chunker *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
||||||
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
||||||
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
||||||
h := hasher.Sum(nil)
|
h := hasher.Sum(nil)
|
||||||
|
|
@ -316,7 +316,7 @@ func (self *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
func (chunker *TreeChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
||||||
return nil, errAppendOppNotSuported
|
return nil, errAppendOppNotSuported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,44 +332,44 @@ type LazyChunkReader struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements the Joiner interface
|
// implements the Joiner interface
|
||||||
func (self *TreeChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
func (chunker *TreeChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
||||||
return &LazyChunkReader{
|
return &LazyChunkReader{
|
||||||
key: key,
|
key: key,
|
||||||
chunkC: chunkC,
|
chunkC: chunkC,
|
||||||
chunkSize: self.chunkSize,
|
chunkSize: chunker.chunkSize,
|
||||||
branches: self.branches,
|
branches: chunker.branches,
|
||||||
hashSize: self.hashSize,
|
hashSize: chunker.hashSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size is meant to be called on the LazySectionReader
|
// Size is meant to be called on the LazySectionReader
|
||||||
func (self *LazyChunkReader) Size(quitC chan bool) (n int64, err error) {
|
func (reader *LazyChunkReader) Size(quitC chan bool) (n int64, err error) {
|
||||||
if self.chunk != nil {
|
if reader.chunk != nil {
|
||||||
return self.chunk.Size, nil
|
return reader.chunk.Size, nil
|
||||||
}
|
}
|
||||||
chunk := retrieve(self.key, self.chunkC, quitC)
|
chunk := retrieve(reader.key, reader.chunkC, quitC)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
select {
|
select {
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return 0, errors.New("aborted")
|
return 0, errors.New("aborted")
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("root chunk not found for %v", self.key.Hex())
|
return 0, fmt.Errorf("root chunk not found for %v", reader.key.Hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.chunk = chunk
|
reader.chunk = chunk
|
||||||
return chunk.Size, nil
|
return chunk.Size, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// read at can be called numerous times
|
// read at can be called numerous times
|
||||||
// concurrent reads are allowed
|
// concurrent reads are allowed
|
||||||
// Size() needs to be called synchronously on the LazyChunkReader first
|
// Size() needs to be called synchronously on the LazyChunkReader first
|
||||||
func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
func (reader *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
||||||
// this is correct, a swarm doc cannot be zero length, so no EOF is expected
|
// this is correct, a swarm doc cannot be zero length, so no EOF is expected
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
size, err := self.Size(quitC)
|
size, err := reader.Size(quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -380,13 +380,13 @@ func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
||||||
var treeSize int64
|
var treeSize int64
|
||||||
var depth int
|
var depth int
|
||||||
// calculate depth and max treeSize
|
// calculate depth and max treeSize
|
||||||
treeSize = self.chunkSize
|
treeSize = reader.chunkSize
|
||||||
for ; treeSize < size; treeSize *= self.branches {
|
for ; treeSize < size; treeSize *= reader.branches {
|
||||||
depth++
|
depth++
|
||||||
}
|
}
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go self.join(b, off, off+int64(len(b)), depth, treeSize/self.branches, self.chunk, &wg, errC, quitC)
|
go reader.join(b, off, off+int64(len(b)), depth, treeSize/reader.branches, reader.chunk, &wg, errC, quitC)
|
||||||
go func() {
|
go func() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(errC)
|
close(errC)
|
||||||
|
|
@ -404,7 +404,7 @@ func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeSize int64, chunk *Chunk, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) {
|
func (reader *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeSize int64, chunk *Chunk, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) {
|
||||||
defer parentWg.Done()
|
defer parentWg.Done()
|
||||||
// return NewDPA(&LocalStore{})
|
// return NewDPA(&LocalStore{})
|
||||||
|
|
||||||
|
|
@ -412,7 +412,7 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr
|
||||||
|
|
||||||
// find appropriate block level
|
// find appropriate block level
|
||||||
for chunk.Size < treeSize && depth > 0 {
|
for chunk.Size < treeSize && depth > 0 {
|
||||||
treeSize /= self.branches
|
treeSize /= reader.branches
|
||||||
depth--
|
depth--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -449,8 +449,8 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr
|
||||||
}
|
}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(j int64) {
|
go func(j int64) {
|
||||||
childKey := chunk.SData[8+j*self.hashSize : 8+(j+1)*self.hashSize]
|
childKey := chunk.SData[8+j*reader.hashSize : 8+(j+1)*reader.hashSize]
|
||||||
chunk := retrieve(childKey, self.chunkC, quitC)
|
chunk := retrieve(childKey, reader.chunkC, quitC)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
select {
|
select {
|
||||||
case errC <- fmt.Errorf("chunk %v-%v not found", off, off+treeSize):
|
case errC <- fmt.Errorf("chunk %v-%v not found", off, off+treeSize):
|
||||||
|
|
@ -461,7 +461,7 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr
|
||||||
if soff < off {
|
if soff < off {
|
||||||
soff = off
|
soff = off
|
||||||
}
|
}
|
||||||
self.join(b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/self.branches, chunk, wg, errC, quitC)
|
reader.join(b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/reader.branches, chunk, wg, errC, quitC)
|
||||||
}(i)
|
}(i)
|
||||||
} //for
|
} //for
|
||||||
}
|
}
|
||||||
|
|
@ -496,10 +496,10 @@ func retrieve(key Key, chunkC chan *Chunk, quitC chan bool) *Chunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read keeps a cursor so cannot be called simulateously, see ReadAt
|
// Read keeps a cursor so cannot be called simulateously, see ReadAt
|
||||||
func (self *LazyChunkReader) Read(b []byte) (read int, err error) {
|
func (reader *LazyChunkReader) Read(b []byte) (read int, err error) {
|
||||||
read, err = self.ReadAt(b, self.off)
|
read, err = reader.ReadAt(b, reader.off)
|
||||||
|
|
||||||
self.off += int64(read)
|
reader.off += int64(read)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,12 @@ type chunkerTester struct {
|
||||||
t test
|
t test
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
func (tester *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
||||||
// reset
|
// reset
|
||||||
self.chunks = make(map[string]*Chunk)
|
tester.chunks = make(map[string]*Chunk)
|
||||||
|
|
||||||
if self.inputs == nil {
|
if tester.inputs == nil {
|
||||||
self.inputs = make(map[uint64][]byte)
|
tester.inputs = make(map[uint64][]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
|
|
@ -64,8 +64,8 @@ func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, c
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return nil
|
return nil
|
||||||
case chunk := <-chunkC:
|
case chunk := <-chunkC:
|
||||||
// self.chunks = append(self.chunks, chunk)
|
// tester.chunks = append(tester.chunks, chunk)
|
||||||
self.chunks[chunk.Key.String()] = chunk
|
tester.chunks[chunk.Key.String()] = chunk
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +89,7 @@ func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, c
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
func (tester *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
timeout := time.After(60 * time.Second)
|
timeout := time.After(60 * time.Second)
|
||||||
if chunkC != nil {
|
if chunkC != nil {
|
||||||
|
|
@ -102,10 +102,10 @@ func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader,
|
||||||
return nil
|
return nil
|
||||||
case chunk := <-chunkC:
|
case chunk := <-chunkC:
|
||||||
if chunk != nil {
|
if chunk != nil {
|
||||||
stored, success := self.chunks[chunk.Key.String()]
|
stored, success := tester.chunks[chunk.Key.String()]
|
||||||
if !success {
|
if !success {
|
||||||
// Requesting data
|
// Requesting data
|
||||||
self.chunks[chunk.Key.String()] = chunk
|
tester.chunks[chunk.Key.String()] = chunk
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +135,7 @@ func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader,
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Chunk, quitC chan bool) LazySectionReader {
|
func (tester *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Chunk, quitC chan bool) LazySectionReader {
|
||||||
// reset but not the chunks
|
// reset but not the chunks
|
||||||
|
|
||||||
reader := chunker.Join(key, chunkC)
|
reader := chunker.Join(key, chunkC)
|
||||||
|
|
@ -153,7 +153,7 @@ func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Ch
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// this just mocks the behaviour of a chunk store retrieval
|
// this just mocks the behaviour of a chunk store retrieval
|
||||||
stored, success := self.chunks[chunk.Key.String()]
|
stored, success := tester.chunks[chunk.Key.String()]
|
||||||
if !success {
|
if !success {
|
||||||
return errors.New("Not found")
|
return errors.New("Not found")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,12 @@ func testDataReader(l int) (r io.Reader) {
|
||||||
return io.LimitReader(rand.Reader, int64(l))
|
return io.LimitReader(rand.Reader, int64(l))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *brokenLimitedReader) Read(buf []byte) (int, error) {
|
func (reader *brokenLimitedReader) Read(buf []byte) (int, error) {
|
||||||
if self.off+len(buf) > self.errAt {
|
if reader.off+len(buf) > reader.errAt {
|
||||||
return 0, fmt.Errorf("Broken reader")
|
return 0, fmt.Errorf("Broken reader")
|
||||||
}
|
}
|
||||||
self.off += len(buf)
|
reader.off += len(buf)
|
||||||
return self.lr.Read(buf)
|
return reader.lr.Read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDataReaderAndSlice(l int) (r io.Reader, slice []byte) {
|
func testDataReaderAndSlice(l int) (r io.Reader, slice []byte) {
|
||||||
|
|
|
||||||
|
|
@ -45,27 +45,27 @@ func NewLDBDatabase(file string) (*LDBDatabase, error) {
|
||||||
return database, nil
|
return database, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Put(key []byte, value []byte) {
|
func (database *LDBDatabase) Put(key []byte, value []byte) {
|
||||||
err := self.db.Put(key, value, nil)
|
err := database.db.Put(key, value, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error put", err)
|
fmt.Println("Error put", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
|
func (database *LDBDatabase) Get(key []byte) ([]byte, error) {
|
||||||
dat, err := self.db.Get(key, nil)
|
dat, err := database.db.Get(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return dat, nil
|
return dat, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Delete(key []byte) error {
|
func (database *LDBDatabase) Delete(key []byte) error {
|
||||||
return self.db.Delete(key, nil)
|
return database.db.Delete(key, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) LastKnownTD() []byte {
|
func (database *LDBDatabase) LastKnownTD() []byte {
|
||||||
data, _ := self.Get([]byte("LTD"))
|
data, _ := database.Get([]byte("LTD"))
|
||||||
|
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
data = []byte{0x0}
|
data = []byte{0x0}
|
||||||
|
|
@ -74,15 +74,15 @@ func (self *LDBDatabase) LastKnownTD() []byte {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) NewIterator() iterator.Iterator {
|
func (database *LDBDatabase) NewIterator() iterator.Iterator {
|
||||||
return self.db.NewIterator(nil, nil)
|
return database.db.NewIterator(nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Write(batch *leveldb.Batch) error {
|
func (database *LDBDatabase) Write(batch *leveldb.Batch) error {
|
||||||
return self.db.Write(batch, nil)
|
return database.db.Write(batch, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Close() {
|
func (database *LDBDatabase) Close() {
|
||||||
// Close the leveldb database
|
// Close the leveldb database
|
||||||
self.db.Close()
|
database.db.Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -559,12 +559,12 @@ type dbSyncIterator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialises a sync iterator from a syncToken (passed in with the handshake)
|
// initialises a sync iterator from a syncToken (passed in with the handshake)
|
||||||
func (self *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err error) {
|
func (store *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err error) {
|
||||||
if state.First > state.Last {
|
if state.First > state.Last {
|
||||||
return nil, fmt.Errorf("no entries found")
|
return nil, fmt.Errorf("no entries found")
|
||||||
}
|
}
|
||||||
si = &dbSyncIterator{
|
si = &dbSyncIterator{
|
||||||
it: self.db.NewIterator(),
|
it: store.db.NewIterator(),
|
||||||
DbSyncState: state,
|
DbSyncState: state,
|
||||||
}
|
}
|
||||||
si.it.Seek(getIndexKey(state.Start))
|
si.it.Seek(getIndexKey(state.Start))
|
||||||
|
|
@ -573,28 +573,28 @@ func (self *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err
|
||||||
|
|
||||||
// walk the area from Start to Stop and returns items within time interval
|
// walk the area from Start to Stop and returns items within time interval
|
||||||
// First to Last
|
// First to Last
|
||||||
func (self *dbSyncIterator) Next() (key Key) {
|
func (iterator *dbSyncIterator) Next() (key Key) {
|
||||||
for self.it.Valid() {
|
for iterator.it.Valid() {
|
||||||
dbkey := self.it.Key()
|
dbkey := iterator.it.Key()
|
||||||
if dbkey[0] != 0 {
|
if dbkey[0] != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
key = Key(make([]byte, len(dbkey)-1))
|
key = Key(make([]byte, len(dbkey)-1))
|
||||||
copy(key[:], dbkey[1:])
|
copy(key[:], dbkey[1:])
|
||||||
if bytes.Compare(key[:], self.Start) <= 0 {
|
if bytes.Compare(key[:], iterator.Start) <= 0 {
|
||||||
self.it.Next()
|
iterator.it.Next()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if bytes.Compare(key[:], self.Stop) > 0 {
|
if bytes.Compare(key[:], iterator.Stop) > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var index dpaDBIndex
|
var index dpaDBIndex
|
||||||
decodeIndex(self.it.Value(), &index)
|
decodeIndex(iterator.it.Value(), &index)
|
||||||
self.it.Next()
|
iterator.it.Next()
|
||||||
if (index.Idx >= self.First) && (index.Idx < self.Last) {
|
if (index.Idx >= iterator.First) && (index.Idx < iterator.Last) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.it.Release()
|
iterator.it.Release()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,53 +90,53 @@ func NewDPA(store ChunkStore, params *ChunkerParams) *DPA {
|
||||||
// FS-aware API and httpaccess
|
// FS-aware API and httpaccess
|
||||||
// Chunk retrieval blocks on netStore requests with a timeout so reader will
|
// Chunk retrieval blocks on netStore requests with a timeout so reader will
|
||||||
// report error if retrieval of chunks within requested range time out.
|
// report error if retrieval of chunks within requested range time out.
|
||||||
func (self *DPA) Retrieve(key Key) LazySectionReader {
|
func (dpa *DPA) Retrieve(key Key) LazySectionReader {
|
||||||
return self.Chunker.Join(key, self.retrieveC)
|
return dpa.Chunker.Join(key, dpa.retrieveC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API. Main entry point for document storage directly. Used by the
|
// Public API. Main entry point for document storage directly. Used by the
|
||||||
// FS-aware API and httpaccess
|
// FS-aware API and httpaccess
|
||||||
func (self *DPA) Store(data io.Reader, size int64, swg *sync.WaitGroup, wwg *sync.WaitGroup) (key Key, err error) {
|
func (dpa *DPA) Store(data io.Reader, size int64, swg *sync.WaitGroup, wwg *sync.WaitGroup) (key Key, err error) {
|
||||||
return self.Chunker.Split(data, size, self.storeC, swg, wwg)
|
return dpa.Chunker.Split(data, size, dpa.storeC, swg, wwg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) Start() {
|
func (dpa *DPA) Start() {
|
||||||
self.lock.Lock()
|
dpa.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer dpa.lock.Unlock()
|
||||||
if self.running {
|
if dpa.running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.running = true
|
dpa.running = true
|
||||||
self.retrieveC = make(chan *Chunk, retrieveChanCapacity)
|
dpa.retrieveC = make(chan *Chunk, retrieveChanCapacity)
|
||||||
self.storeC = make(chan *Chunk, storeChanCapacity)
|
dpa.storeC = make(chan *Chunk, storeChanCapacity)
|
||||||
self.quitC = make(chan bool)
|
dpa.quitC = make(chan bool)
|
||||||
self.storeLoop()
|
dpa.storeLoop()
|
||||||
self.retrieveLoop()
|
dpa.retrieveLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) Stop() {
|
func (dpa *DPA) Stop() {
|
||||||
self.lock.Lock()
|
dpa.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer dpa.lock.Unlock()
|
||||||
if !self.running {
|
if !dpa.running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.running = false
|
dpa.running = false
|
||||||
close(self.quitC)
|
close(dpa.quitC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieveLoop dispatches the parallel chunk retrieval requests received on the
|
// retrieveLoop dispatches the parallel chunk retrieval requests received on the
|
||||||
// retrieve channel to its ChunkStore (NetStore or LocalStore)
|
// retrieve channel to its ChunkStore (NetStore or LocalStore)
|
||||||
func (self *DPA) retrieveLoop() {
|
func (dpa *DPA) retrieveLoop() {
|
||||||
for i := 0; i < maxRetrieveProcesses; i++ {
|
for i := 0; i < maxRetrieveProcesses; i++ {
|
||||||
go self.retrieveWorker()
|
go dpa.retrieveWorker()
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses))
|
log.Trace(fmt.Sprintf("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) retrieveWorker() {
|
func (dpa *DPA) retrieveWorker() {
|
||||||
for chunk := range self.retrieveC {
|
for chunk := range dpa.retrieveC {
|
||||||
log.Trace(fmt.Sprintf("dpa: retrieve loop : chunk %v", chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("dpa: retrieve loop : chunk %v", chunk.Key.Log()))
|
||||||
storedChunk, err := self.Get(chunk.Key)
|
storedChunk, err := dpa.Get(chunk.Key)
|
||||||
if err == notFound {
|
if err == notFound {
|
||||||
log.Trace(fmt.Sprintf("chunk %v not found", chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("chunk %v not found", chunk.Key.Log()))
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|
@ -148,7 +148,7 @@ func (self *DPA) retrieveWorker() {
|
||||||
close(chunk.C)
|
close(chunk.C)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-self.quitC:
|
case <-dpa.quitC:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
@ -157,24 +157,24 @@ func (self *DPA) retrieveWorker() {
|
||||||
|
|
||||||
// storeLoop dispatches the parallel chunk store request processors
|
// storeLoop dispatches the parallel chunk store request processors
|
||||||
// received on the store channel to its ChunkStore (NetStore or LocalStore)
|
// received on the store channel to its ChunkStore (NetStore or LocalStore)
|
||||||
func (self *DPA) storeLoop() {
|
func (dpa *DPA) storeLoop() {
|
||||||
for i := 0; i < maxStoreProcesses; i++ {
|
for i := 0; i < maxStoreProcesses; i++ {
|
||||||
go self.storeWorker()
|
go dpa.storeWorker()
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("dpa: store spawning %v workers", maxStoreProcesses))
|
log.Trace(fmt.Sprintf("dpa: store spawning %v workers", maxStoreProcesses))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) storeWorker() {
|
func (dpa *DPA) storeWorker() {
|
||||||
|
|
||||||
for chunk := range self.storeC {
|
for chunk := range dpa.storeC {
|
||||||
self.Put(chunk)
|
dpa.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
log.Trace(fmt.Sprintf("dpa: store processor %v", chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("dpa: store processor %v", chunk.Key.Log()))
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-self.quitC:
|
case <-dpa.quitC:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
@ -198,14 +198,14 @@ func NewDpaChunkStore(localStore, netStore ChunkStore) *dpaChunkStore {
|
||||||
|
|
||||||
// Get is the entrypoint for local retrieve requests
|
// Get is the entrypoint for local retrieve requests
|
||||||
// waits for response or times out
|
// waits for response or times out
|
||||||
func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
|
func (store *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
|
||||||
chunk, err = self.netStore.Get(key)
|
chunk, err = store.netStore.Get(key)
|
||||||
// timeout := time.Now().Add(searchTimeout)
|
// timeout := time.Now().Add(searchTimeout)
|
||||||
if chunk.SData != nil {
|
if chunk.SData != nil {
|
||||||
log.Trace(fmt.Sprintf("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData)))
|
log.Trace(fmt.Sprintf("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: use self.timer time.Timer and reset with defer disableTimer
|
// TODO: use store.timer time.Timer and reset with defer disableTimer
|
||||||
timer := time.After(searchTimeout)
|
timer := time.After(searchTimeout)
|
||||||
select {
|
select {
|
||||||
case <-timer:
|
case <-timer:
|
||||||
|
|
@ -218,8 +218,8 @@ func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put is the entrypoint for local store requests coming from storeLoop
|
// Put is the entrypoint for local store requests coming from storeLoop
|
||||||
func (self *dpaChunkStore) Put(entry *Chunk) {
|
func (store *dpaChunkStore) Put(entry *Chunk) {
|
||||||
chunk, err := self.localStore.Get(entry.Key)
|
chunk, err := store.localStore.Get(entry.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace(fmt.Sprintf("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log()))
|
log.Trace(fmt.Sprintf("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log()))
|
||||||
chunk = entry
|
chunk = entry
|
||||||
|
|
@ -232,10 +232,10 @@ func (self *dpaChunkStore) Put(entry *Chunk) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// from this point on the storage logic is the same with network storage requests
|
// from this point on the storage logic is the same with network storage requests
|
||||||
log.Trace(fmt.Sprintf("DPA.Put %v: %v", self.n, chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("DPA.Put %v: %v", store.n, chunk.Key.Log()))
|
||||||
self.n++
|
store.n++
|
||||||
self.netStore.Put(chunk)
|
store.netStore.Put(chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close chunk store
|
// Close chunk store
|
||||||
func (self *dpaChunkStore) Close() {}
|
func (store *dpaChunkStore) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -46,25 +46,25 @@ func NewLocalStore(hash SwarmHasher, params *StoreParams) (*LocalStore, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalStore) CacheCounter() uint64 {
|
func (store *LocalStore) CacheCounter() uint64 {
|
||||||
return uint64(self.memStore.(*MemStore).Counter())
|
return uint64(store.memStore.(*MemStore).Counter())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalStore) DbCounter() uint64 {
|
func (store *LocalStore) DbCounter() uint64 {
|
||||||
return self.DbStore.(*DbStore).Counter()
|
return store.DbStore.(*DbStore).Counter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalStore is itself a chunk store
|
// LocalStore is itstore a chunk store
|
||||||
// unsafe, in that the data is not integrity checked
|
// unsafe, in that the data is not integrity checked
|
||||||
func (self *LocalStore) Put(chunk *Chunk) {
|
func (store *LocalStore) Put(chunk *Chunk) {
|
||||||
chunk.dbStored = make(chan bool)
|
chunk.dbStored = make(chan bool)
|
||||||
self.memStore.Put(chunk)
|
store.memStore.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Add(1)
|
chunk.wg.Add(1)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
dbStorePutCounter.Inc(1)
|
dbStorePutCounter.Inc(1)
|
||||||
self.DbStore.Put(chunk)
|
store.DbStore.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -75,19 +75,19 @@ func (self *LocalStore) Put(chunk *Chunk) {
|
||||||
// This method is blocking until the chunk is retrieved
|
// This method is blocking until the chunk is retrieved
|
||||||
// so additional timeout may be needed to wrap this call if
|
// so additional timeout may be needed to wrap this call if
|
||||||
// ChunkStores are remote and can have long latency
|
// ChunkStores are remote and can have long latency
|
||||||
func (self *LocalStore) Get(key Key) (chunk *Chunk, err error) {
|
func (store *LocalStore) Get(key Key) (chunk *Chunk, err error) {
|
||||||
chunk, err = self.memStore.Get(key)
|
chunk, err = store.memStore.Get(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chunk, err = self.DbStore.Get(key)
|
chunk, err = store.DbStore.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8]))
|
chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8]))
|
||||||
self.memStore.Put(chunk)
|
store.memStore.Put(chunk)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close local store
|
// Close local store
|
||||||
func (self *LocalStore) Close() {}
|
func (store *LocalStore) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ type StoreParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//create params with default values
|
//create params with default values
|
||||||
func NewDefaultStoreParams() (self *StoreParams) {
|
func NewDefaultStoreParams() *StoreParams {
|
||||||
return &StoreParams{
|
return &StoreParams{
|
||||||
DbCapacity: defaultDbCapacity,
|
DbCapacity: defaultDbCapacity,
|
||||||
CacheCapacity: defaultCacheCapacity,
|
CacheCapacity: defaultCacheCapacity,
|
||||||
|
|
@ -68,8 +68,8 @@ func NewDefaultStoreParams() (self *StoreParams) {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *StoreParams) Init(path string) {
|
func (params *StoreParams) Init(path string) {
|
||||||
self.ChunkDbPath = filepath.Join(path, "chunks")
|
params.ChunkDbPath = filepath.Join(path, "chunks")
|
||||||
}
|
}
|
||||||
|
|
||||||
// netstore contructor, takes path argument that is used to initialise dbStore,
|
// netstore contructor, takes path argument that is used to initialise dbStore,
|
||||||
|
|
@ -92,8 +92,8 @@ var (
|
||||||
// ~ unsafe put in localdb no check if exists no extra copy no hash validation
|
// ~ unsafe put in localdb no check if exists no extra copy no hash validation
|
||||||
// the chunk is forced to propagate (Cloud.Store) even if locally found!
|
// the chunk is forced to propagate (Cloud.Store) even if locally found!
|
||||||
// caller needs to make sure if that is wanted
|
// caller needs to make sure if that is wanted
|
||||||
func (self *NetStore) Put(entry *Chunk) {
|
func (store *NetStore) Put(entry *Chunk) {
|
||||||
self.localStore.Put(entry)
|
store.localStore.Put(entry)
|
||||||
|
|
||||||
// handle deliveries
|
// handle deliveries
|
||||||
if entry.Req != nil {
|
if entry.Req != nil {
|
||||||
|
|
@ -102,19 +102,19 @@ func (self *NetStore) Put(entry *Chunk) {
|
||||||
// that the chunk is has been retrieved
|
// that the chunk is has been retrieved
|
||||||
close(entry.Req.C)
|
close(entry.Req.C)
|
||||||
// deliver the chunk to requesters upstream
|
// deliver the chunk to requesters upstream
|
||||||
go self.cloud.Deliver(entry)
|
go store.cloud.Deliver(entry)
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log()))
|
log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log()))
|
||||||
// handle propagating store requests
|
// handle propagating store requests
|
||||||
// go self.cloud.Store(entry)
|
// go store.cloud.Store(entry)
|
||||||
go self.cloud.Store(entry)
|
go store.cloud.Store(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve logic common for local and network chunk retrieval requests
|
// retrieve logic common for local and network chunk retrieval requests
|
||||||
func (self *NetStore) Get(key Key) (*Chunk, error) {
|
func (store *NetStore) Get(key Key) (*Chunk, error) {
|
||||||
var err error
|
var err error
|
||||||
chunk, err := self.localStore.Get(key)
|
chunk, err := store.localStore.Get(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if chunk.Req == nil {
|
if chunk.Req == nil {
|
||||||
log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key))
|
log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key))
|
||||||
|
|
@ -127,10 +127,10 @@ func (self *NetStore) Get(key Key) (*Chunk, error) {
|
||||||
// no data and no request status
|
// no data and no request status
|
||||||
log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key))
|
log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key))
|
||||||
chunk = NewChunk(key, newRequestStatus(key))
|
chunk = NewChunk(key, newRequestStatus(key))
|
||||||
self.localStore.memStore.Put(chunk)
|
store.localStore.memStore.Put(chunk)
|
||||||
go self.cloud.Retrieve(chunk)
|
go store.cloud.Retrieve(chunk)
|
||||||
return chunk, nil
|
return chunk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close netstore
|
// Close netstore
|
||||||
func (self *NetStore) Close() {}
|
func (store *NetStore) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -126,54 +126,54 @@ type PyramidChunker struct {
|
||||||
workerLock sync.RWMutex
|
workerLock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPyramidChunker(params *ChunkerParams) (self *PyramidChunker) {
|
func NewPyramidChunker(params *ChunkerParams) *PyramidChunker {
|
||||||
self = &PyramidChunker{}
|
chunker := &PyramidChunker{}
|
||||||
self.hashFunc = MakeHashFunc(params.Hash)
|
chunker.hashFunc = MakeHashFunc(params.Hash)
|
||||||
self.branches = params.Branches
|
chunker.branches = params.Branches
|
||||||
self.hashSize = int64(self.hashFunc().Size())
|
chunker.hashSize = int64(chunker.hashFunc().Size())
|
||||||
self.chunkSize = self.hashSize * self.branches
|
chunker.chunkSize = chunker.hashSize * chunker.branches
|
||||||
self.workerCount = 0
|
chunker.workerCount = 0
|
||||||
return
|
return chunker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
func (chunker *PyramidChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
||||||
return &LazyChunkReader{
|
return &LazyChunkReader{
|
||||||
key: key,
|
key: key,
|
||||||
chunkC: chunkC,
|
chunkC: chunkC,
|
||||||
chunkSize: self.chunkSize,
|
chunkSize: chunker.chunkSize,
|
||||||
branches: self.branches,
|
branches: chunker.branches,
|
||||||
hashSize: self.hashSize,
|
hashSize: chunker.hashSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) incrementWorkerCount() {
|
func (chunker *PyramidChunker) incrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
chunker.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer chunker.workerLock.Unlock()
|
||||||
self.workerCount += 1
|
chunker.workerCount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) getWorkerCount() int64 {
|
func (chunker *PyramidChunker) getWorkerCount() int64 {
|
||||||
self.workerLock.Lock()
|
chunker.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer chunker.workerLock.Unlock()
|
||||||
return self.workerCount
|
return chunker.workerCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) decrementWorkerCount() {
|
func (chunker *PyramidChunker) decrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
chunker.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer chunker.workerLock.Unlock()
|
||||||
self.workerCount -= 1
|
chunker.workerCount -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
func (chunker *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
||||||
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
rootKey := make([]byte, self.hashSize)
|
rootKey := make([]byte, chunker.hashSize)
|
||||||
chunkLevel := make([][]*TreeEntry, self.branches)
|
chunkLevel := make([][]*TreeEntry, chunker.branches)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go self.prepareChunks(false, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
go chunker.prepareChunks(false, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
||||||
|
|
||||||
// closes internal error channel if all subprocesses in the workgroup finished
|
// closes internal error channel if all subprocesses in the workgroup finished
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -204,20 +204,20 @@ func (self *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
func (chunker *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
rootKey := make([]byte, self.hashSize)
|
rootKey := make([]byte, chunker.hashSize)
|
||||||
chunkLevel := make([][]*TreeEntry, self.branches)
|
chunkLevel := make([][]*TreeEntry, chunker.branches)
|
||||||
|
|
||||||
// Load the right most unfinished tree chunks in every level
|
// Load the right most unfinished tree chunks in every level
|
||||||
self.loadTree(chunkLevel, key, chunkC, quitC)
|
chunker.loadTree(chunkLevel, key, chunkC, quitC)
|
||||||
|
|
||||||
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go self.prepareChunks(true, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
go chunker.prepareChunks(true, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
||||||
|
|
||||||
// closes internal error channel if all subprocesses in the workgroup finished
|
// closes internal error channel if all subprocesses in the workgroup finished
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -245,10 +245,10 @@ func (self *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
func (chunker *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
||||||
defer self.decrementWorkerCount()
|
defer chunker.decrementWorkerCount()
|
||||||
|
|
||||||
hasher := self.hashFunc()
|
hasher := chunker.hashFunc()
|
||||||
if wwg != nil {
|
if wwg != nil {
|
||||||
defer wwg.Done()
|
defer wwg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -259,14 +259,14 @@ func (self *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.processChunk(id, hasher, job, chunkC, swg)
|
chunker.processChunk(id, hasher, job, chunkC, swg)
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
func (chunker *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
||||||
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
||||||
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
||||||
h := hasher.Sum(nil)
|
h := hasher.Sum(nil)
|
||||||
|
|
@ -294,7 +294,7 @@ func (self *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC chan *Chunk, quitC chan bool) error {
|
func (chunker *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC chan *Chunk, quitC chan bool) error {
|
||||||
// Get the root chunk to get the total size
|
// Get the root chunk to get the total size
|
||||||
chunk := retrieve(key, chunkC, quitC)
|
chunk := retrieve(key, chunkC, quitC)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
|
|
@ -302,13 +302,13 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
}
|
}
|
||||||
|
|
||||||
//if data size is less than a chunk... add a parent with update as pending
|
//if data size is less than a chunk... add a parent with update as pending
|
||||||
if chunk.Size <= self.chunkSize {
|
if chunk.Size <= chunker.chunkSize {
|
||||||
newEntry := &TreeEntry{
|
newEntry := &TreeEntry{
|
||||||
level: 0,
|
level: 0,
|
||||||
branchCount: 1,
|
branchCount: 1,
|
||||||
subtreeSize: uint64(chunk.Size),
|
subtreeSize: uint64(chunk.Size),
|
||||||
chunk: make([]byte, self.chunkSize+8),
|
chunk: make([]byte, chunker.chunkSize+8),
|
||||||
key: make([]byte, self.hashSize),
|
key: make([]byte, chunker.hashSize),
|
||||||
index: 0,
|
index: 0,
|
||||||
updatePending: true,
|
updatePending: true,
|
||||||
}
|
}
|
||||||
|
|
@ -319,13 +319,13 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
|
|
||||||
var treeSize int64
|
var treeSize int64
|
||||||
var depth int
|
var depth int
|
||||||
treeSize = self.chunkSize
|
treeSize = chunker.chunkSize
|
||||||
for ; treeSize < chunk.Size; treeSize *= self.branches {
|
for ; treeSize < chunk.Size; treeSize *= chunker.branches {
|
||||||
depth++
|
depth++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the root chunk entry
|
// Add the root chunk entry
|
||||||
branchCount := int64(len(chunk.SData)-8) / self.hashSize
|
branchCount := int64(len(chunk.SData)-8) / chunker.hashSize
|
||||||
newEntry := &TreeEntry{
|
newEntry := &TreeEntry{
|
||||||
level: depth - 1,
|
level: depth - 1,
|
||||||
branchCount: branchCount,
|
branchCount: branchCount,
|
||||||
|
|
@ -343,14 +343,14 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
//TODO(jmozah): instead of loading finished branches and then trim in the end,
|
//TODO(jmozah): instead of loading finished branches and then trim in the end,
|
||||||
//avoid loading them in the first place
|
//avoid loading them in the first place
|
||||||
for _, ent := range chunkLevel[lvl] {
|
for _, ent := range chunkLevel[lvl] {
|
||||||
branchCount = int64(len(ent.chunk)-8) / self.hashSize
|
branchCount = int64(len(ent.chunk)-8) / chunker.hashSize
|
||||||
for i := int64(0); i < branchCount; i++ {
|
for i := int64(0); i < branchCount; i++ {
|
||||||
key := ent.chunk[8+(i*self.hashSize) : 8+((i+1)*self.hashSize)]
|
key := ent.chunk[8+(i*chunker.hashSize) : 8+((i+1)*chunker.hashSize)]
|
||||||
newChunk := retrieve(key, chunkC, quitC)
|
newChunk := retrieve(key, chunkC, quitC)
|
||||||
if newChunk == nil {
|
if newChunk == nil {
|
||||||
return errLoadingTreeChunk
|
return errLoadingTreeChunk
|
||||||
}
|
}
|
||||||
bewBranchCount := int64(len(newChunk.SData)-8) / self.hashSize
|
bewBranchCount := int64(len(newChunk.SData)-8) / chunker.hashSize
|
||||||
newEntry := &TreeEntry{
|
newEntry := &TreeEntry{
|
||||||
level: lvl - 1,
|
level: lvl - 1,
|
||||||
branchCount: bewBranchCount,
|
branchCount: bewBranchCount,
|
||||||
|
|
@ -365,7 +365,7 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to get only the right most unfinished branch.. so trim all finished branches
|
// We need to get only the right most unfinished branch.. so trim all finished branches
|
||||||
if int64(len(chunkLevel[lvl-1])) >= self.branches {
|
if int64(len(chunkLevel[lvl-1])) >= chunker.branches {
|
||||||
chunkLevel[lvl-1] = nil
|
chunkLevel[lvl-1] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +374,7 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEntry, data io.Reader, rootKey []byte, quitC chan bool, wg *sync.WaitGroup, jobC chan *chunkJob, processorWG *sync.WaitGroup, chunkC chan *Chunk, errC chan error, storageWG *sync.WaitGroup) {
|
func (chunker *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEntry, data io.Reader, rootKey []byte, quitC chan bool, wg *sync.WaitGroup, jobC chan *chunkJob, processorWG *sync.WaitGroup, chunkC chan *Chunk, errC chan error, storageWG *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
chunkWG := &sync.WaitGroup{}
|
chunkWG := &sync.WaitGroup{}
|
||||||
|
|
@ -385,10 +385,10 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
processorWG.Add(1)
|
processorWG.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.incrementWorkerCount()
|
chunker.incrementWorkerCount()
|
||||||
go self.processor(self.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
go chunker.processor(chunker.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
||||||
|
|
||||||
parent := NewTreeEntry(self)
|
parent := NewTreeEntry(chunker)
|
||||||
var unFinishedChunk *Chunk
|
var unFinishedChunk *Chunk
|
||||||
|
|
||||||
if isAppend && len(chunkLevel[0]) != 0 {
|
if isAppend && len(chunkLevel[0]) != 0 {
|
||||||
|
|
@ -396,7 +396,7 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
lastIndex := len(chunkLevel[0]) - 1
|
lastIndex := len(chunkLevel[0]) - 1
|
||||||
ent := chunkLevel[0][lastIndex]
|
ent := chunkLevel[0][lastIndex]
|
||||||
|
|
||||||
if ent.branchCount < self.branches {
|
if ent.branchCount < chunker.branches {
|
||||||
parent = &TreeEntry{
|
parent = &TreeEntry{
|
||||||
level: 0,
|
level: 0,
|
||||||
branchCount: ent.branchCount,
|
branchCount: ent.branchCount,
|
||||||
|
|
@ -408,10 +408,10 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBranch := parent.branchCount - 1
|
lastBranch := parent.branchCount - 1
|
||||||
lastKey := parent.chunk[8+lastBranch*self.hashSize : 8+(lastBranch+1)*self.hashSize]
|
lastKey := parent.chunk[8+lastBranch*chunker.hashSize : 8+(lastBranch+1)*chunker.hashSize]
|
||||||
|
|
||||||
unFinishedChunk = retrieve(lastKey, chunkC, quitC)
|
unFinishedChunk = retrieve(lastKey, chunkC, quitC)
|
||||||
if unFinishedChunk.Size < self.chunkSize {
|
if unFinishedChunk.Size < chunker.chunkSize {
|
||||||
|
|
||||||
parent.subtreeSize = parent.subtreeSize - uint64(unFinishedChunk.Size)
|
parent.subtreeSize = parent.subtreeSize - uint64(unFinishedChunk.Size)
|
||||||
parent.branchCount = parent.branchCount - 1
|
parent.branchCount = parent.branchCount - 1
|
||||||
|
|
@ -425,7 +425,7 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
|
|
||||||
var n int
|
var n int
|
||||||
var err error
|
var err error
|
||||||
chunkData := make([]byte, self.chunkSize+8)
|
chunkData := make([]byte, chunker.chunkSize+8)
|
||||||
if unFinishedChunk != nil {
|
if unFinishedChunk != nil {
|
||||||
copy(chunkData, unFinishedChunk.SData)
|
copy(chunkData, unFinishedChunk.SData)
|
||||||
n, err = data.Read(chunkData[8+unFinishedChunk.Size:])
|
n, err = data.Read(chunkData[8+unFinishedChunk.Size:])
|
||||||
|
|
@ -441,7 +441,7 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
if parent.branchCount == 1 {
|
if parent.branchCount == 1 {
|
||||||
// Data is exactly one chunk.. pick the last chunk key as root
|
// Data is exactly one chunk.. pick the last chunk key as root
|
||||||
chunkWG.Wait()
|
chunkWG.Wait()
|
||||||
lastChunksKey := parent.chunk[8 : 8+self.hashSize]
|
lastChunksKey := parent.chunk[8 : 8+chunker.hashSize]
|
||||||
copy(rootKey, lastChunksKey)
|
copy(rootKey, lastChunksKey)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -453,18 +453,18 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
|
|
||||||
// Data ended in chunk boundary.. just signal to start bulding tree
|
// Data ended in chunk boundary.. just signal to start bulding tree
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
chunker.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
pkey := self.enqueueDataChunk(chunkData, uint64(n), parent, chunkWG, jobC, quitC)
|
pkey := chunker.enqueueDataChunk(chunkData, uint64(n), parent, chunkWG, jobC, quitC)
|
||||||
|
|
||||||
// update tree related parent data structures
|
// update tree related parent data structures
|
||||||
parent.subtreeSize += uint64(n)
|
parent.subtreeSize += uint64(n)
|
||||||
parent.branchCount++
|
parent.branchCount++
|
||||||
|
|
||||||
// Data got exhausted... signal to send any parent tree related chunks
|
// Data got exhausted... signal to send any parent tree related chunks
|
||||||
if int64(n) < self.chunkSize {
|
if int64(n) < chunker.chunkSize {
|
||||||
|
|
||||||
// only one data chunk .. so dont add any parent chunk
|
// only one data chunk .. so dont add any parent chunk
|
||||||
if parent.branchCount <= 1 {
|
if parent.branchCount <= 1 {
|
||||||
|
|
@ -473,39 +473,39 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
chunker.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent.branchCount == self.branches {
|
if parent.branchCount == chunker.branches {
|
||||||
self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, false, rootKey)
|
chunker.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, false, rootKey)
|
||||||
parent = NewTreeEntry(self)
|
parent = NewTreeEntry(chunker)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
workers := self.getWorkerCount()
|
workers := chunker.getWorkerCount()
|
||||||
if int64(len(jobC)) > workers && workers < ChunkProcessors {
|
if int64(len(jobC)) > workers && workers < ChunkProcessors {
|
||||||
if processorWG != nil {
|
if processorWG != nil {
|
||||||
processorWG.Add(1)
|
processorWG.Add(1)
|
||||||
}
|
}
|
||||||
self.incrementWorkerCount()
|
chunker.incrementWorkerCount()
|
||||||
go self.processor(self.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
go chunker.processor(chunker.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool, rootKey []byte) {
|
func (chunker *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool, rootKey []byte) {
|
||||||
chunkWG.Wait()
|
chunkWG.Wait()
|
||||||
self.enqueueTreeChunk(chunkLevel, ent, chunkWG, jobC, quitC, last)
|
chunker.enqueueTreeChunk(chunkLevel, ent, chunkWG, jobC, quitC, last)
|
||||||
|
|
||||||
compress := false
|
compress := false
|
||||||
endLvl := self.branches
|
endLvl := chunker.branches
|
||||||
for lvl := int64(0); lvl < self.branches; lvl++ {
|
for lvl := int64(0); lvl < chunker.branches; lvl++ {
|
||||||
lvlCount := int64(len(chunkLevel[lvl]))
|
lvlCount := int64(len(chunkLevel[lvl]))
|
||||||
if lvlCount >= self.branches {
|
if lvlCount >= chunker.branches {
|
||||||
endLvl = lvl + 1
|
endLvl = lvl + 1
|
||||||
compress = true
|
compress = true
|
||||||
break
|
break
|
||||||
|
|
@ -527,9 +527,9 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for startCount := int64(0); startCount < lvlCount; startCount += self.branches {
|
for startCount := int64(0); startCount < lvlCount; startCount += chunker.branches {
|
||||||
|
|
||||||
endCount := startCount + self.branches
|
endCount := startCount + chunker.branches
|
||||||
if endCount > lvlCount {
|
if endCount > lvlCount {
|
||||||
endCount = lvlCount
|
endCount = lvlCount
|
||||||
}
|
}
|
||||||
|
|
@ -545,18 +545,18 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
level: int(lvl + 1),
|
level: int(lvl + 1),
|
||||||
branchCount: 0,
|
branchCount: 0,
|
||||||
subtreeSize: 0,
|
subtreeSize: 0,
|
||||||
chunk: make([]byte, self.chunkSize+8),
|
chunk: make([]byte, chunker.chunkSize+8),
|
||||||
key: make([]byte, self.hashSize),
|
key: make([]byte, chunker.hashSize),
|
||||||
index: int(nextLvlCount),
|
index: int(nextLvlCount),
|
||||||
updatePending: true,
|
updatePending: true,
|
||||||
}
|
}
|
||||||
for index := int64(0); index < lvlCount; index++ {
|
for index := int64(0); index < lvlCount; index++ {
|
||||||
updateEntry.branchCount++
|
updateEntry.branchCount++
|
||||||
updateEntry.subtreeSize += chunkLevel[lvl][index].subtreeSize
|
updateEntry.subtreeSize += chunkLevel[lvl][index].subtreeSize
|
||||||
copy(updateEntry.chunk[8+(index*self.hashSize):8+((index+1)*self.hashSize)], chunkLevel[lvl][index].key[:self.hashSize])
|
copy(updateEntry.chunk[8+(index*chunker.hashSize):8+((index+1)*chunker.hashSize)], chunkLevel[lvl][index].key[:chunker.hashSize])
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enqueueTreeChunk(chunkLevel, updateEntry, chunkWG, jobC, quitC, last)
|
chunker.enqueueTreeChunk(chunkLevel, updateEntry, chunkWG, jobC, quitC, last)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -565,8 +565,8 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
level: int(lvl + 1),
|
level: int(lvl + 1),
|
||||||
branchCount: noOfBranches,
|
branchCount: noOfBranches,
|
||||||
subtreeSize: 0,
|
subtreeSize: 0,
|
||||||
chunk: make([]byte, (noOfBranches*self.hashSize)+8),
|
chunk: make([]byte, (noOfBranches*chunker.hashSize)+8),
|
||||||
key: make([]byte, self.hashSize),
|
key: make([]byte, chunker.hashSize),
|
||||||
index: int(nextLvlCount),
|
index: int(nextLvlCount),
|
||||||
updatePending: false,
|
updatePending: false,
|
||||||
}
|
}
|
||||||
|
|
@ -575,11 +575,11 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
for i := startCount; i < endCount; i++ {
|
for i := startCount; i < endCount; i++ {
|
||||||
entry := chunkLevel[lvl][i]
|
entry := chunkLevel[lvl][i]
|
||||||
newEntry.subtreeSize += entry.subtreeSize
|
newEntry.subtreeSize += entry.subtreeSize
|
||||||
copy(newEntry.chunk[8+(index*self.hashSize):8+((index+1)*self.hashSize)], entry.key[:self.hashSize])
|
copy(newEntry.chunk[8+(index*chunker.hashSize):8+((index+1)*chunker.hashSize)], entry.key[:chunker.hashSize])
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enqueueTreeChunk(chunkLevel, newEntry, chunkWG, jobC, quitC, last)
|
chunker.enqueueTreeChunk(chunkLevel, newEntry, chunkWG, jobC, quitC, last)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -595,7 +595,7 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool) {
|
func (chunker *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool) {
|
||||||
if ent != nil {
|
if ent != nil {
|
||||||
|
|
||||||
// wait for data chunks to get over before processing the tree chunk
|
// wait for data chunks to get over before processing the tree chunk
|
||||||
|
|
@ -604,10 +604,10 @@ func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *Tre
|
||||||
}
|
}
|
||||||
|
|
||||||
binary.LittleEndian.PutUint64(ent.chunk[:8], ent.subtreeSize)
|
binary.LittleEndian.PutUint64(ent.chunk[:8], ent.subtreeSize)
|
||||||
ent.key = make([]byte, self.hashSize)
|
ent.key = make([]byte, chunker.hashSize)
|
||||||
chunkWG.Add(1)
|
chunkWG.Add(1)
|
||||||
select {
|
select {
|
||||||
case jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*self.hashSize+8], int64(ent.subtreeSize), chunkWG, TreeChunk, 0}:
|
case jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*chunker.hashSize+8], int64(ent.subtreeSize), chunkWG, TreeChunk, 0}:
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -622,9 +622,9 @@ func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *Tre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool) Key {
|
func (chunker *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool) Key {
|
||||||
binary.LittleEndian.PutUint64(chunkData[:8], size)
|
binary.LittleEndian.PutUint64(chunkData[:8], size)
|
||||||
pkey := parent.chunk[8+parent.branchCount*self.hashSize : 8+(parent.branchCount+1)*self.hashSize]
|
pkey := parent.chunk[8+parent.branchCount*chunker.hashSize : 8+(parent.branchCount+1)*chunker.hashSize]
|
||||||
|
|
||||||
chunkWG.Add(1)
|
chunkWG.Add(1)
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ type HashWithLength struct {
|
||||||
hash.Hash
|
hash.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HashWithLength) ResetWithLength(length []byte) {
|
func (h *HashWithLength) ResetWithLength(length []byte) {
|
||||||
self.Reset()
|
h.Reset()
|
||||||
self.Write(length)
|
h.Write(length)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,6 @@ type LazyTestSectionReader struct {
|
||||||
*io.SectionReader
|
*io.SectionReader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LazyTestSectionReader) Size(chan bool) (int64, error) {
|
func (reader *LazyTestSectionReader) Size(chan bool) (int64, error) {
|
||||||
return self.SectionReader.Size(), nil
|
return reader.SectionReader.Size(), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
130
swarm/swarm.go
130
swarm/swarm.go
|
|
@ -82,17 +82,17 @@ type SwarmAPI struct {
|
||||||
PrvKey *ecdsa.PrivateKey
|
PrvKey *ecdsa.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) API() *SwarmAPI {
|
func (s *Swarm) API() *SwarmAPI {
|
||||||
return &SwarmAPI{
|
return &SwarmAPI{
|
||||||
Api: self.api,
|
Api: s.api,
|
||||||
Backend: self.backend,
|
Backend: s.backend,
|
||||||
PrvKey: self.privateKey,
|
PrvKey: s.privateKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a new swarm service instance
|
// creates a new swarm service instance
|
||||||
// implements node.Service
|
// implements node.Service
|
||||||
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config) (self *Swarm, err error) {
|
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config) (s *Swarm, err error) {
|
||||||
if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) {
|
if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) {
|
||||||
return nil, fmt.Errorf("empty public key")
|
return nil, fmt.Errorf("empty public key")
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +100,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
|
||||||
return nil, fmt.Errorf("empty bzz key")
|
return nil, fmt.Errorf("empty bzz key")
|
||||||
}
|
}
|
||||||
|
|
||||||
self = &Swarm{
|
s = &Swarm{
|
||||||
config: config,
|
config: config,
|
||||||
swapEnabled: config.SwapEnabled,
|
swapEnabled: config.SwapEnabled,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
|
|
@ -110,7 +110,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
|
||||||
log.Debug(fmt.Sprintf("Setting up Swarm service components"))
|
log.Debug(fmt.Sprintf("Setting up Swarm service components"))
|
||||||
|
|
||||||
hash := storage.MakeHashFunc(config.ChunkerParams.Hash)
|
hash := storage.MakeHashFunc(config.ChunkerParams.Hash)
|
||||||
self.lstore, err = storage.NewLocalStore(hash, config.StoreParams)
|
s.lstore, err = storage.NewLocalStore(hash, config.StoreParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -118,12 +118,12 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
|
||||||
// setup local store
|
// setup local store
|
||||||
log.Debug(fmt.Sprintf("Set up local storage"))
|
log.Debug(fmt.Sprintf("Set up local storage"))
|
||||||
|
|
||||||
self.dbAccess = network.NewDbAccess(self.lstore)
|
s.dbAccess = network.NewDbAccess(s.lstore)
|
||||||
log.Debug(fmt.Sprintf("Set up local db access (iterator/counter)"))
|
log.Debug(fmt.Sprintf("Set up local db access (iterator/counter)"))
|
||||||
|
|
||||||
// set up the kademlia hive
|
// set up the kademlia hive
|
||||||
self.hive = network.NewHive(
|
s.hive = network.NewHive(
|
||||||
common.HexToHash(self.config.BzzKey), // key to hive (kademlia base address)
|
common.HexToHash(s.config.BzzKey), // key to hive (kademlia base address)
|
||||||
config.HiveParams, // configuration parameters
|
config.HiveParams, // configuration parameters
|
||||||
config.SwapEnabled, // SWAP enabled
|
config.SwapEnabled, // SWAP enabled
|
||||||
config.SyncEnabled, // syncronisation enabled
|
config.SyncEnabled, // syncronisation enabled
|
||||||
|
|
@ -131,22 +131,22 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
|
||||||
log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive"))
|
log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive"))
|
||||||
|
|
||||||
// setup cloud storage backend
|
// setup cloud storage backend
|
||||||
self.cloud = network.NewForwarder(self.hive)
|
s.cloud = network.NewForwarder(s.hive)
|
||||||
log.Debug(fmt.Sprintf("-> set swarm forwarder as cloud storage backend"))
|
log.Debug(fmt.Sprintf("-> set swarm forwarder as cloud storage backend"))
|
||||||
|
|
||||||
// setup cloud storage internal access layer
|
// setup cloud storage internal access layer
|
||||||
self.storage = storage.NewNetStore(hash, self.lstore, self.cloud, config.StoreParams)
|
s.storage = storage.NewNetStore(hash, s.lstore, s.cloud, config.StoreParams)
|
||||||
log.Debug(fmt.Sprintf("-> swarm net store shared access layer to Swarm Chunk Store"))
|
log.Debug(fmt.Sprintf("-> swarm net store shared access layer to Swarm Chunk Store"))
|
||||||
|
|
||||||
// set up Depo (storage handler = cloud storage access layer for incoming remote requests)
|
// set up Depo (storage handler = cloud storage access layer for incoming remote requests)
|
||||||
self.depo = network.NewDepo(hash, self.lstore, self.storage)
|
s.depo = network.NewDepo(hash, s.lstore, s.storage)
|
||||||
log.Debug(fmt.Sprintf("-> REmote Access to CHunks"))
|
log.Debug(fmt.Sprintf("-> REmote Access to CHunks"))
|
||||||
|
|
||||||
// set up DPA, the cloud storage local access layer
|
// set up DPA, the cloud storage local access layer
|
||||||
dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage)
|
dpaChunkStore := storage.NewDpaChunkStore(s.lstore, s.storage)
|
||||||
log.Debug(fmt.Sprintf("-> Local Access to Swarm"))
|
log.Debug(fmt.Sprintf("-> Local Access to Swarm"))
|
||||||
// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage
|
// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage
|
||||||
self.dpa = storage.NewDPA(dpaChunkStore, self.config.ChunkerParams)
|
s.dpa = storage.NewDPA(dpaChunkStore, s.config.ChunkerParams)
|
||||||
log.Debug(fmt.Sprintf("-> Content Store API"))
|
log.Debug(fmt.Sprintf("-> Content Store API"))
|
||||||
|
|
||||||
if len(config.EnsAPIs) > 0 {
|
if len(config.EnsAPIs) > 0 {
|
||||||
|
|
@ -159,17 +159,17 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.
|
||||||
}
|
}
|
||||||
opts = append(opts, api.MultiResolverOptionWithResolver(r, tld))
|
opts = append(opts, api.MultiResolverOptionWithResolver(r, tld))
|
||||||
}
|
}
|
||||||
self.dns = api.NewMultiResolver(opts...)
|
s.dns = api.NewMultiResolver(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.api = api.NewApi(self.dpa, self.dns)
|
s.api = api.NewApi(s.dpa, s.dns)
|
||||||
// Manifests for Smart Hosting
|
// Manifests for Smart Hosting
|
||||||
log.Debug(fmt.Sprintf("-> Web3 virtual server API"))
|
log.Debug(fmt.Sprintf("-> Web3 virtual server API"))
|
||||||
|
|
||||||
self.sfs = fuse.NewSwarmFS(self.api)
|
s.sfs = fuse.NewSwarmFS(s.api)
|
||||||
log.Debug("-> Initializing Fuse file system")
|
log.Debug("-> Initializing Fuse file system")
|
||||||
|
|
||||||
return self, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseEnsAPIAddress parses string according to format
|
// parseEnsAPIAddress parses string according to format
|
||||||
|
|
@ -272,7 +272,7 @@ Start is called when the stack is started
|
||||||
* TODO: start subservices like sword, swear, swarmdns
|
* TODO: start subservices like sword, swear, swarmdns
|
||||||
*/
|
*/
|
||||||
// implements the node.Service interface
|
// implements the node.Service interface
|
||||||
func (self *Swarm) Start(srv *p2p.Server) error {
|
func (s *Swarm) Start(srv *p2p.Server) error {
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
connectPeer := func(url string) error {
|
connectPeer := func(url string) error {
|
||||||
node, err := discover.ParseNode(url)
|
node, err := discover.ParseNode(url)
|
||||||
|
|
@ -283,85 +283,85 @@ func (self *Swarm) Start(srv *p2p.Server) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// set chequebook
|
// set chequebook
|
||||||
if self.swapEnabled {
|
if s.swapEnabled {
|
||||||
ctx := context.Background() // The initial setup has no deadline.
|
ctx := context.Background() // The initial setup has no deadline.
|
||||||
err := self.SetChequebook(ctx)
|
err := s.SetChequebook(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
|
return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook()))
|
log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", s.config.Swap.Chequebook()))
|
||||||
} else {
|
} else {
|
||||||
log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set"))
|
log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set"))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn(fmt.Sprintf("Starting Swarm service"))
|
log.Warn(fmt.Sprintf("Starting Swarm service"))
|
||||||
self.hive.Start(
|
s.hive.Start(
|
||||||
discover.PubkeyID(&srv.PrivateKey.PublicKey),
|
discover.PubkeyID(&srv.PrivateKey.PublicKey),
|
||||||
func() string { return srv.ListenAddr },
|
func() string { return srv.ListenAddr },
|
||||||
connectPeer,
|
connectPeer,
|
||||||
)
|
)
|
||||||
log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.Addr()))
|
log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", s.hive.Addr()))
|
||||||
|
|
||||||
self.dpa.Start()
|
s.dpa.Start()
|
||||||
log.Debug(fmt.Sprintf("Swarm DPA started"))
|
log.Debug(fmt.Sprintf("Swarm DPA started"))
|
||||||
|
|
||||||
// start swarm http proxy server
|
// start swarm http proxy server
|
||||||
if self.config.Port != "" {
|
if s.config.Port != "" {
|
||||||
addr := net.JoinHostPort(self.config.ListenAddr, self.config.Port)
|
addr := net.JoinHostPort(s.config.ListenAddr, s.config.Port)
|
||||||
go httpapi.StartHttpServer(self.api, &httpapi.ServerConfig{
|
go httpapi.StartHttpServer(s.api, &httpapi.ServerConfig{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
CorsString: self.corsString,
|
CorsString: s.corsString,
|
||||||
})
|
})
|
||||||
log.Info(fmt.Sprintf("Swarm http proxy started on %v", addr))
|
log.Info(fmt.Sprintf("Swarm http proxy started on %v", addr))
|
||||||
|
|
||||||
if self.corsString != "" {
|
if s.corsString != "" {
|
||||||
log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.corsString))
|
log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", s.corsString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.periodicallyUpdateGauges()
|
s.periodicallyUpdateGauges()
|
||||||
|
|
||||||
startCounter.Inc(1)
|
startCounter.Inc(1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) periodicallyUpdateGauges() {
|
func (s *Swarm) periodicallyUpdateGauges() {
|
||||||
ticker := time.NewTicker(updateGaugesPeriod)
|
ticker := time.NewTicker(updateGaugesPeriod)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
self.updateGauges()
|
s.updateGauges()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) updateGauges() {
|
func (s *Swarm) updateGauges() {
|
||||||
dbSizeGauge.Update(int64(self.lstore.DbCounter()))
|
dbSizeGauge.Update(int64(s.lstore.DbCounter()))
|
||||||
cacheSizeGauge.Update(int64(self.lstore.CacheCounter()))
|
cacheSizeGauge.Update(int64(s.lstore.CacheCounter()))
|
||||||
uptimeGauge.Update(time.Since(startTime).Nanoseconds())
|
uptimeGauge.Update(time.Since(startTime).Nanoseconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements the node.Service interface
|
// implements the node.Service interface
|
||||||
// stops all component services.
|
// stops all component services.
|
||||||
func (self *Swarm) Stop() error {
|
func (s *Swarm) Stop() error {
|
||||||
self.dpa.Stop()
|
s.dpa.Stop()
|
||||||
err := self.hive.Stop()
|
err := s.hive.Stop()
|
||||||
if ch := self.config.Swap.Chequebook(); ch != nil {
|
if ch := s.config.Swap.Chequebook(); ch != nil {
|
||||||
ch.Stop()
|
ch.Stop()
|
||||||
ch.Save()
|
ch.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.lstore != nil {
|
if s.lstore != nil {
|
||||||
self.lstore.DbStore.Close()
|
s.lstore.DbStore.Close()
|
||||||
}
|
}
|
||||||
self.sfs.Stop()
|
s.sfs.Stop()
|
||||||
stopCounter.Inc(1)
|
stopCounter.Inc(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements the node.Service interface
|
// implements the node.Service interface
|
||||||
func (self *Swarm) Protocols() []p2p.Protocol {
|
func (s *Swarm) Protocols() []p2p.Protocol {
|
||||||
proto, err := network.Bzz(self.depo, self.backend, self.hive, self.dbAccess, self.config.Swap, self.config.SyncParams, self.config.NetworkId)
|
proto, err := network.Bzz(s.depo, s.backend, s.hive, s.dbAccess, s.config.Swap, s.config.SyncParams, s.config.NetworkId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -370,32 +370,32 @@ func (self *Swarm) Protocols() []p2p.Protocol {
|
||||||
|
|
||||||
// implements node.Service
|
// implements node.Service
|
||||||
// Apis returns the RPC Api descriptors the Swarm implementation offers
|
// Apis returns the RPC Api descriptors the Swarm implementation offers
|
||||||
func (self *Swarm) APIs() []rpc.API {
|
func (s *Swarm) APIs() []rpc.API {
|
||||||
return []rpc.API{
|
return []rpc.API{
|
||||||
// public APIs
|
// public APIs
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: &Info{self.config, chequebook.ContractParams},
|
Service: &Info{s.config, chequebook.ContractParams},
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
// admin APIs
|
// admin APIs
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: api.NewControl(self.api, self.hive),
|
Service: api.NewControl(s.api, s.hive),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "chequebook",
|
Namespace: "chequebook",
|
||||||
Version: chequebook.Version,
|
Version: chequebook.Version,
|
||||||
Service: chequebook.NewApi(self.config.Swap.Chequebook),
|
Service: chequebook.NewApi(s.config.Swap.Chequebook),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "swarmfs",
|
Namespace: "swarmfs",
|
||||||
Version: fuse.Swarmfs_Version,
|
Version: fuse.Swarmfs_Version,
|
||||||
Service: self.sfs,
|
Service: s.sfs,
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
// storage APIs
|
// storage APIs
|
||||||
|
|
@ -403,36 +403,36 @@ func (self *Swarm) APIs() []rpc.API {
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: api.NewStorage(self.api),
|
Service: api.NewStorage(s.api),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: api.NewFileSystem(self.api),
|
Service: api.NewFileSystem(s.api),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
// {Namespace, Version, api.NewAdmin(self), false},
|
// {Namespace, Version, api.NewAdmin(s), false},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) Api() *api.Api {
|
func (s *Swarm) Api() *api.Api {
|
||||||
return self.api
|
return s.api
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChequebook ensures that the local checquebook is set up on chain.
|
// SetChequebook ensures that the local checquebook is set up on chain.
|
||||||
func (self *Swarm) SetChequebook(ctx context.Context) error {
|
func (s *Swarm) SetChequebook(ctx context.Context) error {
|
||||||
err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path)
|
err := s.config.Swap.SetChequebook(ctx, s.backend, s.config.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex()))
|
log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", s.config.Swap.Contract.Hex()))
|
||||||
self.hive.DropAll()
|
s.hive.DropAll()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local swarm without netStore
|
// Local swarm without netStore
|
||||||
func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
|
func NewLocalSwarm(datadir, port string) (s *Swarm, err error) {
|
||||||
|
|
||||||
prvKey, err := crypto.GenerateKey()
|
prvKey, err := crypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -449,7 +449,7 @@ func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self = &Swarm{
|
s = &Swarm{
|
||||||
api: api.NewApi(dpa, nil),
|
api: api.NewApi(dpa, nil),
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
@ -463,6 +463,6 @@ type Info struct {
|
||||||
*chequebook.Params
|
*chequebook.Params
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Info) Info() *Info {
|
func (s *Info) Info() *Info {
|
||||||
return self
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue