Commit Graph

272 Commits

Author SHA1 Message Date
Joost Jager
07d289c14e
routing: add SendPaymentAsync to router 2019-06-05 12:41:51 +02:00
Joost Jager
87d3207baf
channeldb+routing: move control tower interface to routing
This commit creates an empty shall for control tower in the routing
package. It is a preparation for adding event notification.
2019-06-05 12:41:47 +02:00
Joost Jager
19d5f8f82c
routing: move default cltv assignment out of router
This commit lifts default setting up to the rpc server level, in line
with other payment defaults.
2019-06-05 12:41:43 +02:00
Olaoluwa Osuntokun
7453dbeacc
Merge pull request #2802 from joostjager/probability
routing: probability based path finding
2019-06-05 11:30:55 +02:00
Johan T. Halseth
1161d87eec
routing/router: correct SendToRoute's amount record in DB
Previously we would mistakenly use the payment value from the dummy
LightningPayment struct, which would obviously be 0 always. Now we
instead calculate the value from the given route.
2019-06-04 10:13:33 +02:00
Joost Jager
7133f37bb8
routing: global probability based mission control
Previously every payment had its own local mission control state which
was in effect only for that payment. In this commit most of the local
state is removed and payments all tap into the global mission control
probability estimator.

Furthermore the decay time of pruned edges and nodes is extended, so
that observations about the network can better benefit future payment
processes.

Last, the probability function is transformed from a binary output to a
gradual curve, allowing for a better trade off between candidate routes.
2019-06-04 10:00:25 +02:00
Joost Jager
68f2a04f42
routerrpc: expose mission control reset rpc 2019-06-04 10:00:17 +02:00
Olaoluwa Osuntokun
4068e78af6
Merge pull request #2717 from cfromknecht/send-payment-payreq
lnrpc+rpcserver: display payreq via listpayments
2019-05-31 17:09:04 -07:00
Conner Fromknecht
078734b511
routing/router: set payreq before persisting PaymentCreationInfo 2019-05-29 16:31:12 -07:00
Joost Jager
cbfc7dd42d
routing: check findPath error 2019-05-29 14:07:00 +02:00
Joost Jager
0e273a5731
routing: return structured error for send to route 2019-05-29 14:06:58 +02:00
Johan T. Halseth
3f76bc0629
routing+server: define PaymentSessionSource 2019-05-27 20:18:59 +02:00
Johan T. Halseth
f4306b1178
routing/payment_session+router: make PaymentSession interface 2019-05-27 20:18:58 +02:00
Johan T. Halseth
adc4640f4f
routing: export MissionControl 2019-05-27 20:18:58 +02:00
Johan T. Halseth
3323800e02
routing/router: resume payment state machine at startup
On startup the router will fetch the in-flight payments from the control
tower, and resume their execution.
2019-05-27 20:18:58 +02:00
Johan T. Halseth
de1bf8a518
routing/router: persist payment state machine
This commit makes the router use the ControlTower to drive the payment
life cycle state machine, to keep track of active payments across
restarts.  This lets the router resume payments on startup, such that
their final results can be handled and stored when ready.
2019-05-27 20:18:58 +02:00
Johan T. Halseth
83bfaa4fb4
routing: extract payment flow into method on paymentLifecycle
This encapsulates all state needed to resume a payment from any point of
the payment flow, and that must be shared between the different stages
of the execution. This is done to prepare for breaking the send loop
into smaller parts, and being able to resume the payment from any point
from persistent state.
2019-05-27 20:18:57 +02:00
Johan T. Halseth
ae7bf2cb7b
routing/router: move sending and receiving payment result into loop 2019-05-27 20:18:57 +02:00
Wilmer Paulino
6e0084fec9
Merge pull request #3075 from cfromknecht/crtr-nil-path-curves
routing/router: nil path pubkeys before spewing
2019-05-23 20:01:54 -07:00
Johan T. Halseth
cd02c22977
htlcswitch+router: move deobfuscator creation to GetPaymentResult call
In this commit we move handing the deobfuscator from the router to the
switch from when the payment is initiated, to when the result is
queried.

We do this because only the router can recreate the deobfuscator after a
restart, and we are preparing for being able to handle results across
restarts.

Since the deobfuscator cannot be nil anymore, we can also get rid of
that special case.
2019-05-16 23:56:12 +02:00
Johan T. Halseth
5a8b892bb6
routing/router: extract sessionKey generation
We extract the session key such that we can later store it across
restarts.
2019-05-16 23:56:12 +02:00
Johan T. Halseth
ec087a9f73
htlcswitch+router: define PaymentResult, GetPaymentResult
This lets us distinguish an critical error from a actual payment result
(success or failure). This is important since we know that we can only
attempt another payment when a final result from the previous payment
attempt is received.
2019-05-16 23:56:12 +02:00
Johan T. Halseth
ed81cec0fa
routing/router: remove sendToSwitch method 2019-05-16 23:56:11 +02:00
Johan T. Halseth
c9e8ff6a34
switch+router+server: move NextPaymentID to router
This commit moves the responsibility of generating a unique payment ID
from the switch to the router. This will make it easier for the router
to keep track of which HTLCs were successfully forwarded onto the
network, as it can query the switch for existing HTLCs as long as the
paymentIDs are kept.

The router is expected to maintain a map from paymentHash->paymentID,
such that they can be replayed on restart. This also lets the router
check the status of a sent payment after a restart, by querying the
switch for the paymentID in question.
2019-05-16 23:56:06 +02:00
Johan T. Halseth
f1cb54f943
routing/router: define PaymentAttemptDispatcher interface
The switch satisfies this interface, and makes it easy to mock the send
method from the router.
2019-05-16 23:53:08 +02:00
Joost Jager
ba3fa94268
lnrpc+routing: Only accept a single route for SendToRoute 2019-05-15 11:54:46 +02:00
Conner Fromknecht
4d26e90ef3
routing/router: nil path pubkeys before spewing 2019-05-14 20:32:58 -07:00
Olaoluwa Osuntokun
f8c824fb1d
Merge pull request #3054 from joostjager/remove-k-shortest
lnrpc+routing: remove k shortest path finding
2019-05-10 15:51:01 -07:00
Johan T. Halseth
10070ecab7
lnwallet: make BlockChainIO.GetUTXO take cancel chan
Use quit channels as cancel chan for call to GetUTXO.
2019-05-09 14:44:47 +02:00
Joost Jager
7a5bd29a69
lnrpc+routing: remove k shortest path finding 2019-05-07 19:54:06 +02:00
Conner Fromknecht
3f59e31248
routing/router: break rescans on router quit
This commit reevaluates the router's quit channel between each block
during the initial call to syncGraphWithChain, which, in the worst case,
may have to scan several thousand blocks on startup if the node has not
been active for some time. Without this, attempting to stop the daemon
will not exit until the rescan has completed, which for certain backends
could be several hours.
2019-05-06 15:04:40 -07:00
Olaoluwa Osuntokun
bab957382f
router: convert Route.ToHopPayloads() to Route.ToSphinxPath()
In this commit, we update the process that we use to generate a sphinx
packet to send our onion routed HTLC. Due to recent changes in the
`sphinx` package we use, we now need to use a new PaymentPath struct. As
a result, it no longer makes sense to split up the nodes in a route and
their per hop paylods as they're now in the same struct. All tests have
been updated accordingly.
2019-04-30 20:13:32 -07:00
Johan T. Halseth
ee257fd0eb
multi: move Route to sub-pkg routing/route 2019-04-29 14:52:33 +02:00
Wilmer Paulino
0b0a9f4172
channeldb+routing: refactor DeleteChannelEdge to use ChannelID
In this commit, we refactor DeleteChannelEdge to use ChannelIDs rather
than ChannelPoints. We do this as the only use of DeleteChannelEdge is
when we are pruning zombie channels from our graph. When running under a
light client, we are unable to obtain the ChannelPoint of each edge due
to the expensive operations required to do so. As a stop-gap, we'll
resort towards using an edge's ChannelID instead, which is already
gossiped between nodes.
2019-04-18 21:57:41 -07:00
Wilmer Paulino
f2637d63ba
routing: prevent fetching blocks for graph edges with AssumeChannelValid
This serves as a stop-gap for light clients as blocks need to be
downloaded from the P2P network, and even with caches, would be too
costly for them to verify. Doing this has two side effects however:
we'll no longer know of the channel capacity and outpoint, which are
essential for some of lnd's responsibilities.
2019-04-18 21:57:37 -07:00
Wilmer Paulino
fd1aa478a9
routing: disable FilteredChainView when AssumeChannelValid is active
In this commit, we disable attempting to determine when a channel has
been closed out on-chain whenever AssumeChannelValid is active. Since
the flag indicates that performing this operation is expensive, we do
this as a temporary optimization until we can include proofs of channels
being closed in the gossip protocol.

With this change, the only way for channels being removed from the graph
will be once they're considered zombies: which can happen when both
edges of a channel have their disabled bits set or when both edges
haven't had an update within the past two weeks.
2019-04-18 21:57:37 -07:00
Wilmer Paulino
7e7b8a1940
routing: prune graph nodes after pruning zombie channels
We do this to ensure we don't leave any stray nodes in our graph that
were part of the zombie channels that we've pruned.
2019-04-18 21:57:36 -07:00
Wilmer Paulino
7eb720e535
routing: mark policy as stale if edge remains double disabled
To ensure we don't mark an edge as live again just because an update
with a fresh timestamp was received, we'll ensure that we reject any
new updates for zombie channels if they remain disabled when running
with AssumeChannelValid.
2019-04-18 21:57:35 -07:00
Wilmer Paulino
f23c3b488e
routing: prune channels with disabled bit set on both edges
In this commit, we add an additional heuristic when running with
AssumeChannelValid. Since AssumeChannelValid being present assumes that
we're not able to quickly determine whether channels are valid, we also
assume that any channels with the disabled bit set on both sides are
considered zombie. This should be relatively safe to do, since the
disabled bits are usually set when the channel is closed on-chain. In
the case that they aren't, we'll have to wait until both edges haven't
had a new update within two weeks to prune them.
2019-04-18 21:57:34 -07:00
Wilmer Paulino
78bdcbb115
routing: prune channels only if both edges are present
We do this to ensure we don't prune too aggressively, as it's possible
that we've only received the channel announcement for a channel, but not
its accompanying channel updates.
2019-04-18 21:57:31 -07:00
Olaoluwa Osuntokun
373927fb3e
Merge pull request #2950 from joostjager/remove-route-cache
routing: remove route cache
2019-04-17 19:34:19 -07:00
Johan T. Halseth
2b9efcbaeb
routing/router: define ErrRouterShuttingDown 2019-04-15 16:55:10 +02:00
Joost Jager
3b94627c12
routing: remove route cache
This commit removes the QueryRoutes route cache. It is causing wrong
routes to be returned because not all of the request parameters are
stored.

The cache allowed high frequency QueryRoutes calls to the same
destination and with the same amount to be returned fast. This behaviour
can also be achieved by caching the request on the client side. In case
a route is invalidated because of for example a channel update,
the subsequent SendToRoute call will fail. This is a trigger to call
QueryRoutes again for a fresh route.
2019-04-13 08:10:32 +02:00
Wilmer Paulino
23796d3247
routing+discovery: extend ChannelGraphSource with zombie index methods 2019-03-27 13:07:30 -07:00
Wilmer Paulino
174645fcba
routing+server: expose DefaultChannelPruneExpiry 2019-03-27 13:07:13 -07:00
Wilmer Paulino
c82d73a826
channeldb+routing: extend edge lookup methods with zombie index check
In this commit, we extend the graph's FetchChannelEdgesByID and
HasChannelEdge methods to also check the zombie index whenever the edge
to be looked up doesn't exist within the edge index. We do this to
signal to callers that the edge is known, but only as a zombie, and the
only information that we have about the edge are the node public keys of
the two parties involved in the edge.

In the event that an edge does exist within the zombie index, we make
an additional check on edge policies to ensure they are not within the
router's pruning window, indicating that it is a fresh update.
2019-03-27 13:06:57 -07:00
Joost Jager
06cd64cbbc
routing: add cltv limit to payment session 2019-03-19 10:36:51 +01:00
Joost Jager
2be1051fb6
zpay32: move HopHint and DefaultFinalCLTVDelta 2019-03-15 10:08:32 +01:00
Joost Jager
6cc82b4a34
routing: add todo describing route cache bug 2019-03-06 15:31:09 +01:00
Joost Jager
c62c9d64da
routing: add source parameter to query routes
This commit allows execution of QueryRoutes from any source node.
Previously this was restricted to only the self node.
2019-03-06 15:31:03 +01:00
Joost Jager
7719bc432f
routing: take Vertex types as path finding source and target nodes
Currently public keys are represented either as a 33-byte array (Vertex) or as a
btcec.PublicKey struct. The latter isn't useable as index into maps and
cannot be used easily in compares. Therefore the 33-byte array
representation is used predominantly throughout the code base.

This commit converts the argument types of source and target nodes for
path finding to Vertex. Path finding executes no crypto operations and
using Vertex simplifies the code.

Additionally, it prepares for the path finding source parameter to be
exposed over rpc in a follow up commit without requiring conversion back
and forth between Vertex and btcec.PublicKey.
2019-03-06 15:31:00 +01:00
Joost Jager
b09adc3219
lnrpc+routing: add edges and nodes restrictions to query routes
This commit allows the execution of QueryRoutes to be controlled using
lists of black-listed edges and nodes. Any path returned will not pass
through the edges and/or nodes on the list.
2019-03-06 15:30:57 +01:00
Joost Jager
b2b28b49b1
routing: export RestrictParams and EdgeLocator 2019-03-06 15:30:52 +01:00
Joost Jager
4937304732
routing: remove redundant fee limit check in newRoute
This check was a left over from when the fee limit wasn't checked yet in
the path finding algorithm.
2019-03-06 15:30:49 +01:00
Johan T. Halseth
cee18892b5
Merge pull request #2565 from joostjager/sendpayment-refactor
routing: sendPayment broken down into multiple functions
2019-03-06 10:20:20 +01:00
Johan T. Halseth
23ce82f4e3
routing/router: don't apply channel policy updates for unknown channels 2019-02-14 14:21:18 +01:00
Johan T. Halseth
1259bacd49
routing: remove unused code, nodeIndex and chanIndex 2019-02-13 12:23:45 +01:00
Joost Jager
f8721ffbca
routing: sendPayment broken down into multiple functions 2019-02-11 08:42:41 +01:00
Joost Jager
7c30a8c493
routing: add outgoing channel restriction 2019-02-08 23:05:56 +01:00
Joost Jager
9e012ecc93
multi: move Input interface and related code
This commit is a step to split the lnwallet package. It puts the Input
interface and implementations in a separate package along with all their
dependencies from lnwallet.
2019-01-31 13:25:33 +01:00
orbitalturtle
08750f180b multi: deprecate IncorrectHtlcAmount onion error
In this commit, we deprecate the `IncorrectHtlcAmount` onion error.
We'll still decode this error to use when retrying paths, but we'll no
longer send this ourselves. The `UnknownPaymentHash` error has been
amended to also include the value of the payment as well. This allows us
to worry about one less error.
2019-01-29 18:21:13 -08:00
Valentine Wallace
cced754659
routing/router: when applying onion failure channel update, set max htlc
In this commit, we ensure that when we update an edge
as a result of a ChannelUpdate being returned from an
onion failure, the max htlc portion of the channel update
is included in the edge update.
2019-01-22 08:42:29 +01:00
Valentine Wallace
15168c391e
discovery+routing: validate msg flags and max htlc in ChannelUpdates
In this commit, we alter the ValidateChannelUpdateAnn function in
ann_validation to validate a remote ChannelUpdate's message flags
and max HTLC field. If the message flag is set but the max HTLC
field is not set or vice versa, the ChannelUpdate fails validation.

Co-authored-by: Johan T. Halseth <johanth@gmail.com>
2019-01-22 08:42:27 +01:00
Valentine Wallace
0fd6004958
multi: partition lnwire.ChanUpdateFlag into ChannelFlags and MessageFlags
In this commit:

* we partition lnwire.ChanUpdateFlag into two (ChanUpdateChanFlags and
ChanUpdateMsgFlags), from a uint16 to a pair of uint8's

* we rename the ChannelUpdate.Flags to ChannelFlags and add an
additional MessageFlags field, which will be used to indicate the
presence of the optional field HtlcMaximumMsat within the ChannelUpdate.

* we partition ChannelEdgePolicy.Flags into message and channel flags.
This change corresponds to the partitioning of the ChannelUpdate's Flags
field into MessageFlags and ChannelFlags.

Co-authored-by: Johan T. Halseth <johanth@gmail.com>
2019-01-22 08:42:26 +01:00
Conner Fromknecht
a5b22788bf
routing/router: avoid naked spew of channel policies 2019-01-09 23:54:41 -08:00
Johan T. Halseth
81fe6e73ed
router+graph: return ErrGraphNodesNotFound if no nodes to prune
Avoids creating a bucket unneccessarily.
2018-12-06 10:22:15 +01:00
Joost Jager
3ed16837e4
routing: prune channels unidirectional
In this commit we introduce pruning of channel edges instead of channels.
Channel failures apply to a single direction and it is unnecessarily
restricting to prune both directions.
2018-12-05 14:39:23 +01:00
Joost Jager
8b8e82a171
routing: remove route hop maps
Hop maps were used in a test to verify the population of the hop map
itself and further only in a single function (getFailedChannelID).
Rewrote that function and removed the hop maps completely.
2018-12-05 14:39:23 +01:00
Olaoluwa Osuntokun
5075394617
Merge pull request #1706 from joostjager/errorprocessing
routing: make routing retry behaviour consistent
2018-12-03 18:29:07 -08:00
Joost Jager
b6ce03e569
routing: make routing retry behaviour consistent
Fixes the following issues:
- If the channel update of FailFeeInsufficient contains an invalid channel
  update, it is not possible to properly add to the failed channels set.
- FailAmountBelowMinimum may apply a channel update, but does not retry.
- FailIncorrectCltvExpiry immediately prunes the vertex without
  trying one more time.

In this commit, the logic for all three policy related errors is
aligned.
2018-12-03 13:23:27 +01:00
Olaoluwa Osuntokun
1fd3aac925
multi: switch from bolt packge to bbolt package for all imports 2018-11-29 20:33:49 -08:00
Joost Jager
6ba1144528
routing: move failed channels map into payment session
This is a small preparatory step towards moving mission control logic
out of router and reusing the acquired routing result data.
2018-11-29 10:31:38 +01:00
Joost Jager
71037969b7
routing: remove pruneVertexFailure function 2018-11-29 10:31:38 +01:00
Joost Jager
aca136a91c
routing: remove unused pruneVertexFailure parameters 2018-11-29 10:31:38 +01:00
Joost Jager
dd7e2e9e04
routing: move logging into applyChannelUpdate
To remove code duplicated at all call sites to check err and log.
2018-11-29 10:31:38 +01:00
Wilmer Paulino
4f45e339f1
discovery+routing: add FetchLightningNode to ChannelGraphSource interface 2018-11-11 17:48:05 -08:00
Wilmer Paulino
18ecb31983
routing/router: extend ChannelGraphSource interface with IsPublicNode
method
2018-10-24 17:28:54 -07:00
Olaoluwa Osuntokun
fbd91feace
Merge pull request #1888 from joostjager/routestruct
lnrpc+routing: fix unmarshallRoute and simplify route structure
2018-10-23 17:07:23 -07:00
Joost Jager
1d97cf1229
htlcswitch+routing: implement expiry_too_far failure
In this commit we add a check to HtlcSatifiesPolicy to verify that the
time lock for the outgoing htlc that is requested in the onion packet
isn't too far in the future.

Without this check, anyone could force an unreasonably long time lock on
the forwarding node.
2018-10-15 08:51:08 +02:00
Joost Jager
a779004a18
lnrpc+routing: fix issues with missing data in unmarshallRoute
In this commit the dependency of unmarshallRoute on edge policies being
available is removed. Edge policies may be unknown and reported as nil.
SendToRoute does not need the policies, but it does need pubkeys of the
route hops. In this commit, unmarshallRoute is modified so that it
takes the pubkeys from edgeInfo instead of channelEdgePolicy.

In addition to this, the route structure is simplified. No more connection
to the database at that point. Fees are determined based on incoming and
outgoing amounts.
2018-10-13 22:59:23 +02:00
Joost Jager
a7fec827cc
routing: validate channel update in failure message 2018-09-11 20:12:09 +02:00
Conner Fromknecht
1e473b2364
routing/router: add assume chan valid 2018-09-03 20:15:12 -07:00
Johan T. Halseth
4b04e1afd1
routing: return ErrRejected if found in reject cache
We make sure to return an error other than ErrIgnored, as ErrIgnored is
expected to only be returned for updates where we already have the
necessary information in the database.

In case of a channel ID found in the rejectCache, there was a
possibility that we had rejected an invalid update for this channel
earlier, and when attempting to add the current update we wouldn't
distinguish the failure to add from an outdated/ignored update.
2018-08-23 07:40:40 +02:00
Johan T. Halseth
18e680f192
router: simplify edge outdated logic, return ErrOutdated if old. 2018-08-23 07:40:39 +02:00
Wilmer Paulino
6c903393e5 router+server: use first hop channel id rather than node key 2018-08-20 21:04:52 -07:00
Joost Jager
3e7473f4f0 routing: backward searching 2018-08-09 20:23:40 -07:00
Joost Jager
6c918a1806 channeldb: store unknown policies in database
The commit ensures that for every channel, there will always
be two entries in the edges bucket. If the policy from one or
both ends of the channel is unknown, it is marked as such.

This allows efficient lookup of incoming edges. This is
required for backwards payment path finding.
2018-08-09 20:23:40 -07:00
Olaoluwa Osuntokun
8c0a151cec
routing: update UTXO verification to use new interface, graph pruning too 2018-07-31 21:28:55 -07:00
Olaoluwa Osuntokun
a6c814010c
routing: exit gracefully if generateSphinxPacket is passed a nil set of hops 2018-07-30 13:41:06 -07:00
Olaoluwa Osuntokun
ef56f76200
routing: demote channel update logging to trace 2018-07-23 17:01:39 -07:00
Olaoluwa Osuntokun
2e75499787
channeldb+routing: move adding shell nodes into db txn of AddChannelEdge
In this commit, we fix a slight race condition that can occur when we go
to add a shell node for a node announcement, but then right afterwards,
a new block arrives that causes us to prune an unconnected node. To
ensure this doesn't happen, we now add shell nodes within the same db
transaction as AddChannelEdge. This ensures that the state is fully
consistent and shell nodes will be added atomically along with the new
channel edge.

As a result of this change, we no longer need to add shell nodes within
the ChannelRouter, as the database will take care of this operation as
it should.
2018-07-22 21:02:53 -07:00
Olaoluwa Osuntokun
f8cbe34e93
routing: prune nodes from the channel graph on start up 2018-07-21 19:52:26 -07:00
Olaoluwa Osuntokun
6f60f139f4 multi: switch over import paths from roasbeef/* to btcsuite/* 2018-07-13 17:05:39 -07:00
Olaoluwa Osuntokun
39c1f46f85
routing: new newLogClosure to delay spew evaluation until log print time
In this commit, we update the generateSphinxPacket to use newLogClosure
to delay the spew evaluation until log print time. Before this commit,
even if we weren't on the trace logging level, the spew call would
always be evaluated.
2018-06-30 17:14:28 -05:00
Wilmer Paulino
ddf8f2cb01
routing: allow specifying a fee limit during route construction 2018-06-12 18:14:48 -07:00
Wilmer Paulino
6a6de812ba
routing: denote a payment's fee limit in millisatoshis instead 2018-06-12 18:14:47 -07:00
Sebastian Delgado
6746609ec6
Add constant and percentage-based fee limits to payments
- Extend SendRequest and QueryRoutesRequest protos
- newRoute function takes fee limit and cuts off routes that exceed it
- queryRoutes, payInvoice and sendPayment commands take the feeLimit inputs and pass them down to newRoute
- When no feeLimit is included, don't enforce any feeLimits at all (by setting feeLimit to maxValue)
2018-06-12 18:14:43 -07:00
Olaoluwa Osuntokun
eb65b0cd5a
routing: check to see if pubkey is nil before logging in sendPayment
In this commit, we now need to check to see if the pubkey is nil as if
the user specified a set of manual routes, then the dest pubkey would be
empty.
2018-06-06 20:45:56 -07:00
Olaoluwa Osuntokun
0113035f6d
routing: add new NewPaymentSessionFromRoutes function instead of interface
In this commit, we modify the recent refactoring of the mission control
sub-system to overload the existing payment session, rather than create
a brand new one. This allows us to re-use more of the existing logic, and
also feedback into mission control the failures incurred by any user
selected routes.
2018-06-06 20:45:56 -07:00
t4sk
53eb396ae9 routing/router: add SendToRoute 2018-06-06 20:45:00 -07:00