package handler import ( "encoding/binary" "time" "ripple/commands" "ripple/services" "ripple/state" "ripple/transport" "ripple/types" ) type AccountHandlers struct { st *state.State pm *services.PaymentManager accSender *transport.AccountTransport cptSender *transport.CounterpartTransport } func NewAccountHandlers( st *state.State, pm *services.PaymentManager, accSender *transport.AccountTransport, cptSender *transport.CounterpartTransport, ) *AccountHandlers { return &AccountHandlers{ st: st, pm: pm, accSender: accSender, cptSender: cptSender, } } func (h *AccountHandlers) FindPath(id types.UserIdentifier, args []byte) { if len(args) < 40 { return } var paymentID [32]byte copy(paymentID[:], args[:32]) amount := int64(binary.BigEndian.Uint64(args[32:40])) pf, ok := h.st.Memory.Pathfinding[paymentID] if !ok { if h.pm.AddPathfinding(paymentID, amount, id) { argsBuf := make([]byte, 33) copy(argsBuf[:32], paymentID[:]) h.accSender.Send(id, types.Instruction{ Command: commands.ACCOUNT_PATH_RECURSE, Arguments: argsBuf, }) } return } if pf.Timeout < time.Now().Unix() { delete(h.st.Memory.Pathfinding, paymentID) return } if pf.Counterpart != (types.UserIdentifier{}) { var cmd byte if pf.Amount < 0 { if amount < 0 || pf.Commit { return } amountPos := -pf.Amount bandwidth := h.pm.PreviewBandwidthOut(id) if bandwidth < amountPos { return } pf.Outgoing = id pf.SetCommit() h.st.Memory.Commit[id][paymentID] = struct{}{} cmd = commands.ACCOUNT_PREPARE_PATH } else { if amount >= 0 || pf.Incoming != (types.UserIdentifier{}) { return } pf.Incoming = id cmd = commands.ACCOUNT_PATH_FOUND } h.st.Memory.Pathfinding[paymentID] = pf h.accSender.Send(id, types.Instruction{ Command: cmd, Arguments: paymentID[:], }) return } if pf.PathFound() { return } var pathFound bool if amount < 0 { if pf.Incoming == (types.UserIdentifier{}) { pf.Incoming = id pathFound = true } else if pf.Incoming != id { return } } else { if pf.Outgoing == (types.UserIdentifier{}) { pf.Outgoing = id pathFound = true } else if pf.Outgoing != id { return } } if pathFound { h.st.Memory.Pathfinding[paymentID] = pf h.accSender.Send(pf.Incoming, types.Instruction{ Command: commands.ACCOUNT_PATH_FOUND, Arguments: paymentID[:], }) return } h.pm.ForwardFindPath(paymentID) } func (h *AccountHandlers) PathRecurse(id types.UserIdentifier, args []byte) { if len(args) < 33 { return } var paymentID [32]byte copy(paymentID[:], args[:32]) depth := args[32] pf, ok := h.st.Memory.GetPathfinding(paymentID) if !ok || depth < pf.Depth { return } if pf.Counterpart != (types.UserIdentifier{}) { pf.Depth = depth + 1 h.st.Memory.Pathfinding[paymentID] = pf h.cptSender.Send(types.Instruction{Command: commands.COUNTERPART_FIND_PATH}) return } if pf.PathFound() { return } pf.Depth = depth + 1 h.st.Memory.Pathfinding[paymentID] = pf var prev types.UserIdentifier if pf.Amount < 0 { prev = pf.Incoming } else { prev = pf.Outgoing } argsBuf := make([]byte, 33) copy(argsBuf[:32], paymentID[:]) argsBuf[32] = pf.Depth h.accSender.Send(prev, types.Instruction{ Command: commands.ACCOUNT_PATH_RECURSE, Arguments: argsBuf, }) } func (h *AccountHandlers) PathFound(id types.UserIdentifier, args []byte) { if len(args) < 32 { return } var paymentID [32]byte copy(paymentID[:], args[:32]) pf, ok := h.st.Memory.GetPathfinding(paymentID) if !ok { return } if pf.Counterpart != (types.UserIdentifier{}) { if pf.Amount >= 0 || pf.Commit { return } amountPos := -pf.Amount bandwidth := h.pm.PreviewBandwidthOut(id) if bandwidth < amountPos { return } pf.Outgoing = id pf.SetCommit() h.st.Memory.Pathfinding[paymentID] = pf h.st.Memory.Commit[id][paymentID] = struct{}{} h.accSender.Send(id, types.Instruction{ Command: commands.ACCOUNT_PREPARE_PATH, Arguments: paymentID[:], }) return } if pf.PathFound() || pf.Incoming == (types.UserIdentifier{}) { return } pf.Outgoing = id h.st.Memory.Pathfinding[paymentID] = pf h.accSender.Send(pf.Incoming, types.Instruction{ Command: commands.ACCOUNT_PATH_FOUND, Arguments: paymentID[:], }) } func (h *AccountHandlers) PreparePath(id types.UserIdentifier, args []byte) { if len(args) < 32 { return } var paymentID [32]byte copy(paymentID[:], args[:32]) pf, ok := h.st.Memory.GetPathfinding(paymentID) if !ok { return } if pf.Counterpart != (types.UserIdentifier{}) { if pf.Amount < 0 || pf.Commit { return } bandwidthIn := h.pm.PreviewBandwidthIn(id) if bandwidthIn < pf.Amount { return } pf.Incoming = id pf.SetCommit() h.st.Memory.Pathfinding[paymentID] = pf h.st.Memory.Commit[id][paymentID] = struct{}{} h.cptSender.Send(types.Instruction{Command: commands.COUNTERPART_COMMIT_PAYMENT}) return } var amountPos int64 if pf.Amount < 0 { amountPos = -pf.Amount } else { amountPos = pf.Amount } bandwidthIn := h.pm.PreviewBandwidthIn(id) bandwidthOut := h.pm.PreviewBandwidthOut(pf.Outgoing) if bandwidthIn < amountPos || bandwidthOut < amountPos { return } pf.Incoming = id pf.SetCommit() h.st.Memory.Pathfinding[paymentID] = pf h.st.Memory.Commit[id][paymentID] = struct{}{} h.accSender.Send(pf.Outgoing, types.Instruction{ Command: commands.ACCOUNT_PREPARE_PATH, Arguments: paymentID[:], }) }