github.com/DxChainNetwork/dxc@v0.8.1-0.20220824085222-1162e304b6e7/p2p/nodestate/nodestate.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package nodestate 18 19 import ( 20 "errors" 21 "reflect" 22 "sync" 23 "time" 24 "unsafe" 25 26 "github.com/DxChainNetwork/dxc/common/mclock" 27 "github.com/DxChainNetwork/dxc/ethdb" 28 "github.com/DxChainNetwork/dxc/log" 29 "github.com/DxChainNetwork/dxc/metrics" 30 "github.com/DxChainNetwork/dxc/p2p/enode" 31 "github.com/DxChainNetwork/dxc/p2p/enr" 32 "github.com/DxChainNetwork/dxc/rlp" 33 ) 34 35 var ( 36 ErrInvalidField = errors.New("invalid field type") 37 ErrClosed = errors.New("already closed") 38 ) 39 40 type ( 41 // NodeStateMachine implements a network node-related event subscription system. 42 // It can assign binary state flags and fields of arbitrary type to each node and allows 43 // subscriptions to flag/field changes which can also modify further flags and fields, 44 // potentially triggering further subscriptions. An operation includes an initial change 45 // and all resulting subsequent changes and always ends in a consistent global state. 46 // It is initiated by a "top level" SetState/SetField call that blocks (also blocking other 47 // top-level functions) until the operation is finished. Callbacks making further changes 48 // should use the non-blocking SetStateSub/SetFieldSub functions. The tree of events 49 // resulting from the initial changes is traversed in a breadth-first order, ensuring for 50 // each subscription callback that all other callbacks caused by the same change triggering 51 // the current callback are processed before anything is triggered by the changes made in the 52 // current callback. In practice this logic ensures that all subscriptions "see" events in 53 // the logical order, callbacks are never called concurrently and "back and forth" effects 54 // are also possible. The state machine design should ensure that infinite event cycles 55 // cannot happen. 56 // The caller can also add timeouts assigned to a certain node and a subset of state flags. 57 // If the timeout elapses, the flags are reset. If all relevant flags are reset then the timer 58 // is dropped. State flags with no timeout are persisted in the database if the flag 59 // descriptor enables saving. If a node has no state flags set at any moment then it is discarded. 60 // Note: in order to avoid mutex deadlocks the callbacks should never lock a mutex that 61 // might be locked when the top level SetState/SetField functions are called. If a function 62 // potentially performs state/field changes then it is recommended to mention this fact in the 63 // function description, along with whether it should run inside an operation callback. 64 NodeStateMachine struct { 65 started, closed bool 66 lock sync.Mutex 67 clock mclock.Clock 68 db ethdb.KeyValueStore 69 dbNodeKey []byte 70 nodes map[enode.ID]*nodeInfo 71 offlineCallbackList []offlineCallback 72 opFlag bool // an operation has started 73 opWait *sync.Cond // signaled when the operation ends 74 opPending []func() // pending callback list of the current operation 75 76 // Registered state flags or fields. Modifications are allowed 77 // only when the node state machine has not been started. 78 setup *Setup 79 fields []*fieldInfo 80 saveFlags bitMask 81 82 // Installed callbacks. Modifications are allowed only when the 83 // node state machine has not been started. 84 stateSubs []stateSub 85 86 // Testing hooks, only for testing purposes. 87 saveNodeHook func(*nodeInfo) 88 } 89 90 // Flags represents a set of flags from a certain setup 91 Flags struct { 92 mask bitMask 93 setup *Setup 94 } 95 96 // Field represents a field from a certain setup 97 Field struct { 98 index int 99 setup *Setup 100 } 101 102 // flagDefinition describes a node state flag. Each registered instance is automatically 103 // mapped to a bit of the 64 bit node states. 104 // If persistent is true then the node is saved when state machine is shutdown. 105 flagDefinition struct { 106 name string 107 persistent bool 108 } 109 110 // fieldDefinition describes an optional node field of the given type. The contents 111 // of the field are only retained for each node as long as at least one of the 112 // state flags is set. 113 fieldDefinition struct { 114 name string 115 ftype reflect.Type 116 encode func(interface{}) ([]byte, error) 117 decode func([]byte) (interface{}, error) 118 } 119 120 // stateSetup contains the list of flags and fields used by the application 121 Setup struct { 122 Version uint 123 flags []flagDefinition 124 fields []fieldDefinition 125 } 126 127 // bitMask describes a node state or state mask. It represents a subset 128 // of node flags with each bit assigned to a flag index (LSB represents flag 0). 129 bitMask uint64 130 131 // StateCallback is a subscription callback which is called when one of the 132 // state flags that is included in the subscription state mask is changed. 133 // Note: oldState and newState are also masked with the subscription mask so only 134 // the relevant bits are included. 135 StateCallback func(n *enode.Node, oldState, newState Flags) 136 137 // FieldCallback is a subscription callback which is called when the value of 138 // a specific field is changed. 139 FieldCallback func(n *enode.Node, state Flags, oldValue, newValue interface{}) 140 141 // nodeInfo contains node state, fields and state timeouts 142 nodeInfo struct { 143 node *enode.Node 144 state bitMask 145 timeouts []*nodeStateTimeout 146 fields []interface{} 147 fieldCount int 148 db, dirty bool 149 } 150 151 nodeInfoEnc struct { 152 Enr enr.Record 153 Version uint 154 State bitMask 155 Fields [][]byte 156 } 157 158 stateSub struct { 159 mask bitMask 160 callback StateCallback 161 } 162 163 nodeStateTimeout struct { 164 mask bitMask 165 timer mclock.Timer 166 } 167 168 fieldInfo struct { 169 fieldDefinition 170 subs []FieldCallback 171 } 172 173 offlineCallback struct { 174 node *nodeInfo 175 state bitMask 176 fields []interface{} 177 } 178 ) 179 180 // offlineState is a special state that is assumed to be set before a node is loaded from 181 // the database and after it is shut down. 182 const offlineState = bitMask(1) 183 184 // NewFlag creates a new node state flag 185 func (s *Setup) NewFlag(name string) Flags { 186 if s.flags == nil { 187 s.flags = []flagDefinition{{name: "offline"}} 188 } 189 f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} 190 s.flags = append(s.flags, flagDefinition{name: name}) 191 return f 192 } 193 194 // NewPersistentFlag creates a new persistent node state flag 195 func (s *Setup) NewPersistentFlag(name string) Flags { 196 if s.flags == nil { 197 s.flags = []flagDefinition{{name: "offline"}} 198 } 199 f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} 200 s.flags = append(s.flags, flagDefinition{name: name, persistent: true}) 201 return f 202 } 203 204 // OfflineFlag returns the system-defined offline flag belonging to the given setup 205 func (s *Setup) OfflineFlag() Flags { 206 return Flags{mask: offlineState, setup: s} 207 } 208 209 // NewField creates a new node state field 210 func (s *Setup) NewField(name string, ftype reflect.Type) Field { 211 f := Field{index: len(s.fields), setup: s} 212 s.fields = append(s.fields, fieldDefinition{ 213 name: name, 214 ftype: ftype, 215 }) 216 return f 217 } 218 219 // NewPersistentField creates a new persistent node field 220 func (s *Setup) NewPersistentField(name string, ftype reflect.Type, encode func(interface{}) ([]byte, error), decode func([]byte) (interface{}, error)) Field { 221 f := Field{index: len(s.fields), setup: s} 222 s.fields = append(s.fields, fieldDefinition{ 223 name: name, 224 ftype: ftype, 225 encode: encode, 226 decode: decode, 227 }) 228 return f 229 } 230 231 // flagOp implements binary flag operations and also checks whether the operands belong to the same setup 232 func flagOp(a, b Flags, trueIfA, trueIfB, trueIfBoth bool) Flags { 233 if a.setup == nil { 234 if a.mask != 0 { 235 panic("Node state flags have no setup reference") 236 } 237 a.setup = b.setup 238 } 239 if b.setup == nil { 240 if b.mask != 0 { 241 panic("Node state flags have no setup reference") 242 } 243 b.setup = a.setup 244 } 245 if a.setup != b.setup { 246 panic("Node state flags belong to a different setup") 247 } 248 res := Flags{setup: a.setup} 249 if trueIfA { 250 res.mask |= a.mask & ^b.mask 251 } 252 if trueIfB { 253 res.mask |= b.mask & ^a.mask 254 } 255 if trueIfBoth { 256 res.mask |= a.mask & b.mask 257 } 258 return res 259 } 260 261 // And returns the set of flags present in both a and b 262 func (a Flags) And(b Flags) Flags { return flagOp(a, b, false, false, true) } 263 264 // AndNot returns the set of flags present in a but not in b 265 func (a Flags) AndNot(b Flags) Flags { return flagOp(a, b, true, false, false) } 266 267 // Or returns the set of flags present in either a or b 268 func (a Flags) Or(b Flags) Flags { return flagOp(a, b, true, true, true) } 269 270 // Xor returns the set of flags present in either a or b but not both 271 func (a Flags) Xor(b Flags) Flags { return flagOp(a, b, true, true, false) } 272 273 // HasAll returns true if b is a subset of a 274 func (a Flags) HasAll(b Flags) bool { return flagOp(a, b, false, true, false).mask == 0 } 275 276 // HasNone returns true if a and b have no shared flags 277 func (a Flags) HasNone(b Flags) bool { return flagOp(a, b, false, false, true).mask == 0 } 278 279 // Equals returns true if a and b have the same flags set 280 func (a Flags) Equals(b Flags) bool { return flagOp(a, b, true, true, false).mask == 0 } 281 282 // IsEmpty returns true if a has no flags set 283 func (a Flags) IsEmpty() bool { return a.mask == 0 } 284 285 // MergeFlags merges multiple sets of state flags 286 func MergeFlags(list ...Flags) Flags { 287 if len(list) == 0 { 288 return Flags{} 289 } 290 res := list[0] 291 for i := 1; i < len(list); i++ { 292 res = res.Or(list[i]) 293 } 294 return res 295 } 296 297 // String returns a list of the names of the flags specified in the bit mask 298 func (f Flags) String() string { 299 if f.mask == 0 { 300 return "[]" 301 } 302 s := "[" 303 comma := false 304 for index, flag := range f.setup.flags { 305 if f.mask&(bitMask(1)<<uint(index)) != 0 { 306 if comma { 307 s = s + ", " 308 } 309 s = s + flag.name 310 comma = true 311 } 312 } 313 s = s + "]" 314 return s 315 } 316 317 // NewNodeStateMachine creates a new node state machine. 318 // If db is not nil then the node states, fields and active timeouts are persisted. 319 // Persistence can be enabled or disabled for each state flag and field. 320 func NewNodeStateMachine(db ethdb.KeyValueStore, dbKey []byte, clock mclock.Clock, setup *Setup) *NodeStateMachine { 321 if setup.flags == nil { 322 panic("No state flags defined") 323 } 324 if len(setup.flags) > 8*int(unsafe.Sizeof(bitMask(0))) { 325 panic("Too many node state flags") 326 } 327 ns := &NodeStateMachine{ 328 db: db, 329 dbNodeKey: dbKey, 330 clock: clock, 331 setup: setup, 332 nodes: make(map[enode.ID]*nodeInfo), 333 fields: make([]*fieldInfo, len(setup.fields)), 334 } 335 ns.opWait = sync.NewCond(&ns.lock) 336 stateNameMap := make(map[string]int) 337 for index, flag := range setup.flags { 338 if _, ok := stateNameMap[flag.name]; ok { 339 panic("Node state flag name collision: " + flag.name) 340 } 341 stateNameMap[flag.name] = index 342 if flag.persistent { 343 ns.saveFlags |= bitMask(1) << uint(index) 344 } 345 } 346 fieldNameMap := make(map[string]int) 347 for index, field := range setup.fields { 348 if _, ok := fieldNameMap[field.name]; ok { 349 panic("Node field name collision: " + field.name) 350 } 351 ns.fields[index] = &fieldInfo{fieldDefinition: field} 352 fieldNameMap[field.name] = index 353 } 354 return ns 355 } 356 357 // stateMask checks whether the set of flags belongs to the same setup and returns its internal bit mask 358 func (ns *NodeStateMachine) stateMask(flags Flags) bitMask { 359 if flags.setup != ns.setup && flags.mask != 0 { 360 panic("Node state flags belong to a different setup") 361 } 362 return flags.mask 363 } 364 365 // fieldIndex checks whether the field belongs to the same setup and returns its internal index 366 func (ns *NodeStateMachine) fieldIndex(field Field) int { 367 if field.setup != ns.setup { 368 panic("Node field belongs to a different setup") 369 } 370 return field.index 371 } 372 373 // SubscribeState adds a node state subscription. The callback is called while the state 374 // machine mutex is not held and it is allowed to make further state updates using the 375 // non-blocking SetStateSub/SetFieldSub functions. All callbacks of an operation are running 376 // from the thread/goroutine of the initial caller and parallel operations are not permitted. 377 // Therefore the callback is never called concurrently. It is the responsibility of the 378 // implemented state logic to avoid deadlocks and to reach a stable state in a finite amount 379 // of steps. 380 // State subscriptions should be installed before loading the node database or making the 381 // first state update. 382 func (ns *NodeStateMachine) SubscribeState(flags Flags, callback StateCallback) { 383 ns.lock.Lock() 384 defer ns.lock.Unlock() 385 386 if ns.started { 387 panic("state machine already started") 388 } 389 ns.stateSubs = append(ns.stateSubs, stateSub{ns.stateMask(flags), callback}) 390 } 391 392 // SubscribeField adds a node field subscription. Same rules apply as for SubscribeState. 393 func (ns *NodeStateMachine) SubscribeField(field Field, callback FieldCallback) { 394 ns.lock.Lock() 395 defer ns.lock.Unlock() 396 397 if ns.started { 398 panic("state machine already started") 399 } 400 f := ns.fields[ns.fieldIndex(field)] 401 f.subs = append(f.subs, callback) 402 } 403 404 // newNode creates a new nodeInfo 405 func (ns *NodeStateMachine) newNode(n *enode.Node) *nodeInfo { 406 return &nodeInfo{node: n, fields: make([]interface{}, len(ns.fields))} 407 } 408 409 // checkStarted checks whether the state machine has already been started and panics otherwise. 410 func (ns *NodeStateMachine) checkStarted() { 411 if !ns.started { 412 panic("state machine not started yet") 413 } 414 } 415 416 // Start starts the state machine, enabling state and field operations and disabling 417 // further subscriptions. 418 func (ns *NodeStateMachine) Start() { 419 ns.lock.Lock() 420 if ns.started { 421 panic("state machine already started") 422 } 423 ns.started = true 424 if ns.db != nil { 425 ns.loadFromDb() 426 } 427 428 ns.opStart() 429 ns.offlineCallbacks(true) 430 ns.opFinish() 431 ns.lock.Unlock() 432 } 433 434 // Stop stops the state machine and saves its state if a database was supplied 435 func (ns *NodeStateMachine) Stop() { 436 ns.lock.Lock() 437 defer ns.lock.Unlock() 438 439 ns.checkStarted() 440 if !ns.opStart() { 441 panic("already closed") 442 } 443 for _, node := range ns.nodes { 444 fields := make([]interface{}, len(node.fields)) 445 copy(fields, node.fields) 446 ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) 447 } 448 if ns.db != nil { 449 ns.saveToDb() 450 } 451 ns.offlineCallbacks(false) 452 ns.closed = true 453 ns.opFinish() 454 } 455 456 // loadFromDb loads persisted node states from the database 457 func (ns *NodeStateMachine) loadFromDb() { 458 it := ns.db.NewIterator(ns.dbNodeKey, nil) 459 for it.Next() { 460 var id enode.ID 461 if len(it.Key()) != len(ns.dbNodeKey)+len(id) { 462 log.Error("Node state db entry with invalid length", "found", len(it.Key()), "expected", len(ns.dbNodeKey)+len(id)) 463 continue 464 } 465 copy(id[:], it.Key()[len(ns.dbNodeKey):]) 466 ns.decodeNode(id, it.Value()) 467 } 468 } 469 470 type dummyIdentity enode.ID 471 472 func (id dummyIdentity) Verify(r *enr.Record, sig []byte) error { return nil } 473 func (id dummyIdentity) NodeAddr(r *enr.Record) []byte { return id[:] } 474 475 // decodeNode decodes a node database entry and adds it to the node set if successful 476 func (ns *NodeStateMachine) decodeNode(id enode.ID, data []byte) { 477 var enc nodeInfoEnc 478 if err := rlp.DecodeBytes(data, &enc); err != nil { 479 log.Error("Failed to decode node info", "id", id, "error", err) 480 return 481 } 482 n, _ := enode.New(dummyIdentity(id), &enc.Enr) 483 node := ns.newNode(n) 484 node.db = true 485 486 if enc.Version != ns.setup.Version { 487 log.Debug("Removing stored node with unknown version", "current", ns.setup.Version, "stored", enc.Version) 488 ns.deleteNode(id) 489 return 490 } 491 if len(enc.Fields) > len(ns.setup.fields) { 492 log.Error("Invalid node field count", "id", id, "stored", len(enc.Fields)) 493 return 494 } 495 // Resolve persisted node fields 496 for i, encField := range enc.Fields { 497 if len(encField) == 0 { 498 continue 499 } 500 if decode := ns.fields[i].decode; decode != nil { 501 if field, err := decode(encField); err == nil { 502 node.fields[i] = field 503 node.fieldCount++ 504 } else { 505 log.Error("Failed to decode node field", "id", id, "field name", ns.fields[i].name, "error", err) 506 return 507 } 508 } else { 509 log.Error("Cannot decode node field", "id", id, "field name", ns.fields[i].name) 510 return 511 } 512 } 513 // It's a compatible node record, add it to set. 514 ns.nodes[id] = node 515 node.state = enc.State 516 fields := make([]interface{}, len(node.fields)) 517 copy(fields, node.fields) 518 ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) 519 log.Debug("Loaded node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) 520 } 521 522 // saveNode saves the given node info to the database 523 func (ns *NodeStateMachine) saveNode(id enode.ID, node *nodeInfo) error { 524 if ns.db == nil { 525 return nil 526 } 527 528 storedState := node.state & ns.saveFlags 529 for _, t := range node.timeouts { 530 storedState &= ^t.mask 531 } 532 enc := nodeInfoEnc{ 533 Enr: *node.node.Record(), 534 Version: ns.setup.Version, 535 State: storedState, 536 Fields: make([][]byte, len(ns.fields)), 537 } 538 log.Debug("Saved node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) 539 lastIndex := -1 540 for i, f := range node.fields { 541 if f == nil { 542 continue 543 } 544 encode := ns.fields[i].encode 545 if encode == nil { 546 continue 547 } 548 blob, err := encode(f) 549 if err != nil { 550 return err 551 } 552 enc.Fields[i] = blob 553 lastIndex = i 554 } 555 if storedState == 0 && lastIndex == -1 { 556 if node.db { 557 node.db = false 558 ns.deleteNode(id) 559 } 560 node.dirty = false 561 return nil 562 } 563 enc.Fields = enc.Fields[:lastIndex+1] 564 data, err := rlp.EncodeToBytes(&enc) 565 if err != nil { 566 return err 567 } 568 if err := ns.db.Put(append(ns.dbNodeKey, id[:]...), data); err != nil { 569 return err 570 } 571 node.dirty, node.db = false, true 572 573 if ns.saveNodeHook != nil { 574 ns.saveNodeHook(node) 575 } 576 return nil 577 } 578 579 // deleteNode removes a node info from the database 580 func (ns *NodeStateMachine) deleteNode(id enode.ID) { 581 ns.db.Delete(append(ns.dbNodeKey, id[:]...)) 582 } 583 584 // saveToDb saves the persistent flags and fields of all nodes that have been changed 585 func (ns *NodeStateMachine) saveToDb() { 586 for id, node := range ns.nodes { 587 if node.dirty { 588 err := ns.saveNode(id, node) 589 if err != nil { 590 log.Error("Failed to save node", "id", id, "error", err) 591 } 592 } 593 } 594 } 595 596 // updateEnode updates the enode entry belonging to the given node if it already exists 597 func (ns *NodeStateMachine) updateEnode(n *enode.Node) (enode.ID, *nodeInfo) { 598 id := n.ID() 599 node := ns.nodes[id] 600 if node != nil && n.Seq() > node.node.Seq() { 601 node.node = n 602 node.dirty = true 603 } 604 return id, node 605 } 606 607 // Persist saves the persistent state and fields of the given node immediately 608 func (ns *NodeStateMachine) Persist(n *enode.Node) error { 609 ns.lock.Lock() 610 defer ns.lock.Unlock() 611 612 ns.checkStarted() 613 if id, node := ns.updateEnode(n); node != nil && node.dirty { 614 err := ns.saveNode(id, node) 615 if err != nil { 616 log.Error("Failed to save node", "id", id, "error", err) 617 } 618 return err 619 } 620 return nil 621 } 622 623 // SetState updates the given node state flags and blocks until the operation is finished. 624 // If a flag with a timeout is set again, the operation removes or replaces the existing timeout. 625 func (ns *NodeStateMachine) SetState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) error { 626 ns.lock.Lock() 627 defer ns.lock.Unlock() 628 629 if !ns.opStart() { 630 return ErrClosed 631 } 632 ns.setState(n, setFlags, resetFlags, timeout) 633 ns.opFinish() 634 return nil 635 } 636 637 // SetStateSub updates the given node state flags without blocking (should be called 638 // from a subscription/operation callback). 639 func (ns *NodeStateMachine) SetStateSub(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { 640 ns.lock.Lock() 641 defer ns.lock.Unlock() 642 643 ns.opCheck() 644 ns.setState(n, setFlags, resetFlags, timeout) 645 } 646 647 func (ns *NodeStateMachine) setState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { 648 ns.checkStarted() 649 set, reset := ns.stateMask(setFlags), ns.stateMask(resetFlags) 650 id, node := ns.updateEnode(n) 651 if node == nil { 652 if set == 0 { 653 return 654 } 655 node = ns.newNode(n) 656 ns.nodes[id] = node 657 } 658 oldState := node.state 659 newState := (node.state & (^reset)) | set 660 changed := oldState ^ newState 661 node.state = newState 662 663 // Remove the timeout callbacks for all reset and set flags, 664 // even they are not existent(it's noop). 665 ns.removeTimeouts(node, set|reset) 666 667 // Register the timeout callback if required 668 if timeout != 0 && set != 0 { 669 ns.addTimeout(n, set, timeout) 670 } 671 if newState == oldState { 672 return 673 } 674 if newState == 0 && node.fieldCount == 0 { 675 delete(ns.nodes, id) 676 if node.db { 677 ns.deleteNode(id) 678 } 679 } else { 680 if changed&ns.saveFlags != 0 { 681 node.dirty = true 682 } 683 } 684 callback := func() { 685 for _, sub := range ns.stateSubs { 686 if changed&sub.mask != 0 { 687 sub.callback(n, Flags{mask: oldState & sub.mask, setup: ns.setup}, Flags{mask: newState & sub.mask, setup: ns.setup}) 688 } 689 } 690 } 691 ns.opPending = append(ns.opPending, callback) 692 } 693 694 // opCheck checks whether an operation is active 695 func (ns *NodeStateMachine) opCheck() { 696 if !ns.opFlag { 697 panic("Operation has not started") 698 } 699 } 700 701 // opStart waits until other operations are finished and starts a new one 702 func (ns *NodeStateMachine) opStart() bool { 703 for ns.opFlag { 704 ns.opWait.Wait() 705 } 706 if ns.closed { 707 return false 708 } 709 ns.opFlag = true 710 return true 711 } 712 713 // opFinish finishes the current operation by running all pending callbacks. 714 // Callbacks resulting from a state/field change performed in a previous callback are always 715 // put at the end of the pending list and therefore processed after all callbacks resulting 716 // from the previous state/field change. 717 func (ns *NodeStateMachine) opFinish() { 718 for len(ns.opPending) != 0 { 719 list := ns.opPending 720 ns.lock.Unlock() 721 for _, cb := range list { 722 cb() 723 } 724 ns.lock.Lock() 725 ns.opPending = ns.opPending[len(list):] 726 } 727 ns.opPending = nil 728 ns.opFlag = false 729 ns.opWait.Broadcast() 730 } 731 732 // Operation calls the given function as an operation callback. This allows the caller 733 // to start an operation with multiple initial changes. The same rules apply as for 734 // subscription callbacks. 735 func (ns *NodeStateMachine) Operation(fn func()) error { 736 ns.lock.Lock() 737 started := ns.opStart() 738 ns.lock.Unlock() 739 if !started { 740 return ErrClosed 741 } 742 fn() 743 ns.lock.Lock() 744 ns.opFinish() 745 ns.lock.Unlock() 746 return nil 747 } 748 749 // offlineCallbacks calls state update callbacks at startup or shutdown 750 func (ns *NodeStateMachine) offlineCallbacks(start bool) { 751 for _, cb := range ns.offlineCallbackList { 752 cb := cb 753 callback := func() { 754 for _, sub := range ns.stateSubs { 755 offState := offlineState & sub.mask 756 onState := cb.state & sub.mask 757 if offState == onState { 758 continue 759 } 760 if start { 761 sub.callback(cb.node.node, Flags{mask: offState, setup: ns.setup}, Flags{mask: onState, setup: ns.setup}) 762 } else { 763 sub.callback(cb.node.node, Flags{mask: onState, setup: ns.setup}, Flags{mask: offState, setup: ns.setup}) 764 } 765 } 766 for i, f := range cb.fields { 767 if f == nil || ns.fields[i].subs == nil { 768 continue 769 } 770 for _, fsub := range ns.fields[i].subs { 771 if start { 772 fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, nil, f) 773 } else { 774 fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, f, nil) 775 } 776 } 777 } 778 } 779 ns.opPending = append(ns.opPending, callback) 780 } 781 ns.offlineCallbackList = nil 782 } 783 784 // AddTimeout adds a node state timeout associated to the given state flag(s). 785 // After the specified time interval, the relevant states will be reset. 786 func (ns *NodeStateMachine) AddTimeout(n *enode.Node, flags Flags, timeout time.Duration) error { 787 ns.lock.Lock() 788 defer ns.lock.Unlock() 789 790 ns.checkStarted() 791 if ns.closed { 792 return ErrClosed 793 } 794 ns.addTimeout(n, ns.stateMask(flags), timeout) 795 return nil 796 } 797 798 // addTimeout adds a node state timeout associated to the given state flag(s). 799 func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time.Duration) { 800 _, node := ns.updateEnode(n) 801 if node == nil { 802 return 803 } 804 mask &= node.state 805 if mask == 0 { 806 return 807 } 808 ns.removeTimeouts(node, mask) 809 t := &nodeStateTimeout{mask: mask} 810 t.timer = ns.clock.AfterFunc(timeout, func() { 811 ns.SetState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0) 812 }) 813 node.timeouts = append(node.timeouts, t) 814 if mask&ns.saveFlags != 0 { 815 node.dirty = true 816 } 817 } 818 819 // removeTimeout removes node state timeouts associated to the given state flag(s). 820 // If a timeout was associated to multiple flags which are not all included in the 821 // specified remove mask then only the included flags are de-associated and the timer 822 // stays active. 823 func (ns *NodeStateMachine) removeTimeouts(node *nodeInfo, mask bitMask) { 824 for i := 0; i < len(node.timeouts); i++ { 825 t := node.timeouts[i] 826 match := t.mask & mask 827 if match == 0 { 828 continue 829 } 830 t.mask -= match 831 if t.mask != 0 { 832 continue 833 } 834 t.timer.Stop() 835 node.timeouts[i] = node.timeouts[len(node.timeouts)-1] 836 node.timeouts = node.timeouts[:len(node.timeouts)-1] 837 i-- 838 if match&ns.saveFlags != 0 { 839 node.dirty = true 840 } 841 } 842 } 843 844 // GetField retrieves the given field of the given node. Note that when used in a 845 // subscription callback the result can be out of sync with the state change represented 846 // by the callback parameters so extra safety checks might be necessary. 847 func (ns *NodeStateMachine) GetField(n *enode.Node, field Field) interface{} { 848 ns.lock.Lock() 849 defer ns.lock.Unlock() 850 851 ns.checkStarted() 852 if ns.closed { 853 return nil 854 } 855 if _, node := ns.updateEnode(n); node != nil { 856 return node.fields[ns.fieldIndex(field)] 857 } 858 return nil 859 } 860 861 // GetState retrieves the current state of the given node. Note that when used in a 862 // subscription callback the result can be out of sync with the state change represented 863 // by the callback parameters so extra safety checks might be necessary. 864 func (ns *NodeStateMachine) GetState(n *enode.Node) Flags { 865 ns.lock.Lock() 866 defer ns.lock.Unlock() 867 868 ns.checkStarted() 869 if ns.closed { 870 return Flags{} 871 } 872 if _, node := ns.updateEnode(n); node != nil { 873 return Flags{mask: node.state, setup: ns.setup} 874 } 875 return Flags{} 876 } 877 878 // SetField sets the given field of the given node and blocks until the operation is finished 879 func (ns *NodeStateMachine) SetField(n *enode.Node, field Field, value interface{}) error { 880 ns.lock.Lock() 881 defer ns.lock.Unlock() 882 883 if !ns.opStart() { 884 return ErrClosed 885 } 886 err := ns.setField(n, field, value) 887 ns.opFinish() 888 return err 889 } 890 891 // SetFieldSub sets the given field of the given node without blocking (should be called 892 // from a subscription/operation callback). 893 func (ns *NodeStateMachine) SetFieldSub(n *enode.Node, field Field, value interface{}) error { 894 ns.lock.Lock() 895 defer ns.lock.Unlock() 896 897 ns.opCheck() 898 return ns.setField(n, field, value) 899 } 900 901 func (ns *NodeStateMachine) setField(n *enode.Node, field Field, value interface{}) error { 902 ns.checkStarted() 903 id, node := ns.updateEnode(n) 904 if node == nil { 905 if value == nil { 906 return nil 907 } 908 node = ns.newNode(n) 909 ns.nodes[id] = node 910 } 911 fieldIndex := ns.fieldIndex(field) 912 f := ns.fields[fieldIndex] 913 if value != nil && reflect.TypeOf(value) != f.ftype { 914 log.Error("Invalid field type", "type", reflect.TypeOf(value), "required", f.ftype) 915 return ErrInvalidField 916 } 917 oldValue := node.fields[fieldIndex] 918 if value == oldValue { 919 return nil 920 } 921 if oldValue != nil { 922 node.fieldCount-- 923 } 924 if value != nil { 925 node.fieldCount++ 926 } 927 node.fields[fieldIndex] = value 928 if node.state == 0 && node.fieldCount == 0 { 929 delete(ns.nodes, id) 930 if node.db { 931 ns.deleteNode(id) 932 } 933 } else { 934 if f.encode != nil { 935 node.dirty = true 936 } 937 } 938 state := node.state 939 callback := func() { 940 for _, cb := range f.subs { 941 cb(n, Flags{mask: state, setup: ns.setup}, oldValue, value) 942 } 943 } 944 ns.opPending = append(ns.opPending, callback) 945 return nil 946 } 947 948 // ForEach calls the callback for each node having all of the required and none of the 949 // disabled flags set. 950 // Note that this callback is not an operation callback but ForEach can be called from an 951 // Operation callback or Operation can also be called from a ForEach callback if necessary. 952 func (ns *NodeStateMachine) ForEach(requireFlags, disableFlags Flags, cb func(n *enode.Node, state Flags)) { 953 ns.lock.Lock() 954 ns.checkStarted() 955 type callback struct { 956 node *enode.Node 957 state bitMask 958 } 959 require, disable := ns.stateMask(requireFlags), ns.stateMask(disableFlags) 960 var callbacks []callback 961 for _, node := range ns.nodes { 962 if node.state&require == require && node.state&disable == 0 { 963 callbacks = append(callbacks, callback{node.node, node.state & (require | disable)}) 964 } 965 } 966 ns.lock.Unlock() 967 for _, c := range callbacks { 968 cb(c.node, Flags{mask: c.state, setup: ns.setup}) 969 } 970 } 971 972 // GetNode returns the enode currently associated with the given ID 973 func (ns *NodeStateMachine) GetNode(id enode.ID) *enode.Node { 974 ns.lock.Lock() 975 defer ns.lock.Unlock() 976 977 ns.checkStarted() 978 if node := ns.nodes[id]; node != nil { 979 return node.node 980 } 981 return nil 982 } 983 984 // AddLogMetrics adds logging and/or metrics for nodes entering, exiting and currently 985 // being in a given set specified by required and disabled state flags 986 func (ns *NodeStateMachine) AddLogMetrics(requireFlags, disableFlags Flags, name string, inMeter, outMeter metrics.Meter, gauge metrics.Gauge) { 987 var count int64 988 ns.SubscribeState(requireFlags.Or(disableFlags), func(n *enode.Node, oldState, newState Flags) { 989 oldMatch := oldState.HasAll(requireFlags) && oldState.HasNone(disableFlags) 990 newMatch := newState.HasAll(requireFlags) && newState.HasNone(disableFlags) 991 if newMatch == oldMatch { 992 return 993 } 994 995 if newMatch { 996 count++ 997 if name != "" { 998 log.Debug("Node entered", "set", name, "id", n.ID(), "count", count) 999 } 1000 if inMeter != nil { 1001 inMeter.Mark(1) 1002 } 1003 } else { 1004 count-- 1005 if name != "" { 1006 log.Debug("Node left", "set", name, "id", n.ID(), "count", count) 1007 } 1008 if outMeter != nil { 1009 outMeter.Mark(1) 1010 } 1011 } 1012 if gauge != nil { 1013 gauge.Update(count) 1014 } 1015 }) 1016 }