profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/achiku/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

achiku/dgw 166

dgw generates Golang struct, and simple Table/Row Data Gateway functions from PostgreSQL table metadata

achiku/go-http-api-server 9

Go 1.7+ HTTP API server sample

achiku/ansible-playbook-lnd 7

Ansible role to install and manage lnd configuration

achiku/cnps 2

See who's coming to your event

achiku/achiku.github.io 0

akirachiku.com

achiku/akirachiku.com 0

https://akirachiku.com using Hugo

achiku/aldjemy 0

Integration SQLAlchemy in Django projects for effective query building purposes

achiku/ansible-go 0

Ansible role that installs Go (http://golang.org/). The latest stable release that has been compiled for x86 64-bit Linux systems is installed by default, and different platforms and versions are supported by modifying the role variables.

achiku/ansible-golang 0

Ansible Go language role

achiku/ansible-openswan 0

ansible openswan role

pull request commentbitcoin/bitcoin

build: Mark print-% target as phony.

Yes this needs squashing.

dgoncharov

comment created time in 18 minutes

push eventpython/mypy

Shantanu

commit sha 379622de482ec16dd1676ad6d183dcfca5203194

Drop Python 3.5 support (#10706)

view details

push time in 34 minutes

PR merged python/mypy

Drop Python 3.5 support
+17 -46

0 comment

12 changed files

hauntsaninja

pr closed time in 34 minutes

Pull request review commentgo-kit/kit

Dependency updates

 require ( 	github.com/go-stack/stack v1.8.0 	github.com/golang/protobuf v1.5.2 	github.com/google/btree v1.0.0 // indirect-	github.com/hashicorp/consul/api v1.3.0+	github.com/hashicorp/consul/api v1.8.1

Looks like v1.9.0 just came out.

sagikazarmark

comment created time in an hour

Pull request review commentgo-kit/kit

Replace aws lambda structs with stubs

 const ( 	KeyEncMode   key = iota ) +// Created based on github.com/aws/aws-lambda-go/events.APIGatewayProxyRequest for the purposes of the tests below.

Consider including the version of the github.com/aws/aws-lambda-go/events package referred to when creating these structs.

sagikazarmark

comment created time in an hour

issue commentallinurl/goaccess

Token '/Sep/2018' doesn't match specifier '%d'

@KasFerreira This should work:

goaccess access.log --log-format='%h [%dT%t-%^] "%v" "%r" %s %b "%R" "%u" %^' --date-format=%Y-%m-%d --time-format=%T
Strandedpirate

comment created time in 2 hours

issue commentallinurl/goaccess

How do you delete stored goaccess data tables / logs

Also, are you using --persist and --restore. If you are, then please don't use them as they would keep restoring from disk whatever data was last parsed.

BobaPearl

comment created time in 2 hours

PR opened lightningnetwork/lnd

lnwallet: prevent anchor reserve enforcement on legacy inbound channel

This PR aims to address a flaw in our anchor reserve enforcement logic in which an inbound "legacy" channel (i.e. a channel with a commitment type that precedes anchors) would be rejected by the recipient if they have at least one opened channel using the anchors commitment type and do not have enough on-chain funds to meet the anchors reserve.

The first commit shows how the test fails due to the bug addressed in the second commit.

Fixes https://github.com/lightningnetwork/lnd/issues/5381.

+88 -69

0 comment

2 changed files

pr created time in 2 hours

issue closedallinurl/goaccess

Difference between hits and visitors

Hi,

I am new to goaccess. I am not sure if I understand the difference between hits and visitors. Any examples to understand better? I am attaching the screenshot for reference.

Screenshot 2021-06-09 at 10 36 25 PM

closed time in 2 hours

kaushalshriyan

issue commentallinurl/goaccess

Difference between hits and visitors

Glad it is working for you :)

#117 will implement that. I'm working on it as we speak and hoping it will be out soon. A workaround would be to use sed, awk, etc.

# sed -n '/'$(date '+%d\/%b\/%Y' -d '1 week ago')'/,$ p' access.log | goaccess -a - -o report.html

The man page has some examples when working with dates.

Stay tuned for the upcoming releases.

Closing this. Feel free to reopen it if needed.

kaushalshriyan

comment created time in 2 hours

pull request commentgo-kit/kit

Remove deprecated kitgen

I looked for it in this repo, the website and issues/PRs. Couldn't find any. Might be worth to update the list in #843

sagikazarmark

comment created time in 2 hours

pull request commentpython/mypy

Add initial singledispatch typechecking support

Diff from mypy_primer, showing the effect of this PR on open source code:

mypy (https://github.com/python/mypy.git)
+ mypy/stubtest.py:230: note: (Skipping most remaining errors due to unresolved imports or missing stubs; fix these first)

pranavrajpal

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase, 		t.Fatalf("SendPayment didn't exit") 	} }++// TestPaymentState tests that the logics implemented on paymentState struct+// are as expected. In particular, that the method terminated and+// needWaitForShards return the right values.+func TestPaymentState(t *testing.T) {+	t.Parallel()++	testCases := []struct {+		name string++		// Use the following three params, each is equivalent to a bool

👍

yyforyongyu

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 func TestChannelOnChainRejectionZombie(t *testing.T) { 	require.Nil(t, err) 	assertChanChainRejection(t, ctx, edge, ErrInvalidFundingOutput) }++func createDummyTestGraph(t *testing.T) *testGraphInstance {+	// Setup two simple channels such that we can mock sending along this+	// route.+	chanCapSat := btcutil.Amount(100000)+	testChannels := []*testChannel{+		symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{+			Expiry:  144,+			FeeRate: 400,+			MinHTLC: 1,+			MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),+		}, 1),+		symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{+			Expiry:  144,+			FeeRate: 400,+			MinHTLC: 1,+			MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),+		}, 2),+	}++	testGraph, err := createTestGraphFromChannels(testChannels, "a")+	require.NoError(t, err, "failed to create graph")+	return testGraph+}++func createDummyLightningPayment(t *testing.T,+	target route.Vertex, amt lnwire.MilliSatoshi) *LightningPayment {++	var preImage lntypes.Preimage+	_, err := rand.Read(preImage[:])+	require.NoError(t, err, "unable to generate preimage")++	payHash := preImage.Hash()++	return &LightningPayment{+		Target:      target,+		Amount:      amt,+		FeeLimit:    noFeeLimit,+		paymentHash: &payHash,+	}+}++// TestSendMPPaymentSucceed tests that we can successfully send a MPPayment via+// router.SendPayment. This test mainly focuses on testing the logic of the+// method resumePayment is implemented as expected.+func TestSendMPPaymentSucceed(t *testing.T) {+	const startingBlockHeight = 101++	// Create mockers to initialize the router.+	controlTower := &mockControlTower{}+	sessionSource := &mockPaymentSessionSource{}+	missionControl := &mockMissionControl{}+	payer := &mockPaymentAttemptDispatcher{}+	chain := newMockChain(startingBlockHeight)+	chainView := newMockChainView(chain)+	testGraph := createDummyTestGraph(t)++	// Define the behavior of the mockers to the point where we can+	// successfully start the router.+	controlTower.On("FetchInFlightPayments").Return(+		[]*channeldb.MPPayment{}, nil,+	)+	payer.On("CleanStore", mock.Anything).Return(nil)++	// Create and start the router.+	router, err := New(Config{+		Control:        controlTower,+		SessionSource:  sessionSource,+		MissionControl: missionControl,+		Payer:          payer,++		// TODO(yy): create new mocks for the chain and chainview.+		Chain:     chain,+		ChainView: chainView,++		// TODO(yy): mock the graph once it's changed into interface.+		Graph: testGraph.graph,++		Clock:              clock.NewTestClock(time.Unix(1, 0)),+		GraphPruneInterval: time.Hour * 2,+		NextPaymentID: func() (uint64, error) {+			next := atomic.AddUint64(&uniquePaymentID, 1)+			return next, nil+		},+	})+	require.NoError(t, err, "failed to create router")++	// Make sure the router can start and stop without error.+	require.NoError(t, router.Start(), "router failed to start")+	defer func() {+		require.NoError(t, router.Stop(), "router failed to stop")+	}()++	// Once the router is started, check that the mocked methods are called+	// as expected.+	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)++	// Mock the methods to the point where we are inside the function+	// resumePayment.+	paymentAmt := lnwire.MilliSatoshi(10000)+	req := createDummyLightningPayment(+		t, testGraph.aliasMap["c"], paymentAmt,+	)+	identifier := lntypes.Hash(req.Identifier())+	session := &mockPaymentSession{}+	sessionSource.On("NewPaymentSession", req).Return(session, nil)+	controlTower.On("InitPayment", identifier, mock.Anything).Return(nil)++	// The following mocked methods are called inside resumePayment. Note+	// that the payment object below will determine the state of the+	// paymentLifecycle.+	payment := &channeldb.MPPayment{}+	controlTower.On("FetchPayment", identifier).Return(payment, nil)++	// Create a route that can send 1/4 of the total amount. This value+	// will be returned by calling RequestRoute.+	shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap)+	require.NoError(t, err, "failed to create route")+	session.On("RequestRoute",+		mock.Anything, mock.Anything, mock.Anything, mock.Anything,+	).Return(shard, nil)++	// Make a new htlc attempt with zero fee and append it to the payment's+	// HTLCs when calling RegisterAttempt.+	activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0)+	controlTower.On("RegisterAttempt",+		identifier, mock.Anything,+	).Return(nil).Run(func(args mock.Arguments) {+		payment.HTLCs = append(payment.HTLCs, activeAttempt)+	})++	// Create a buffered chan and it will be returned by GetPaymentResult.+	payer.resultChan = make(chan *htlcswitch.PaymentResult, 10)+	payer.On("GetPaymentResult",+		mock.Anything, identifier, mock.Anything,+	).Run(func(args mock.Arguments) {+		// Before the mock method is returned, we send the result to+		// the read-only chan.+		payer.resultChan <- &htlcswitch.PaymentResult{}+	})++	// Simple mocking the rest.+	payer.On("SendHTLC",+		mock.Anything, mock.Anything, mock.Anything,+	).Return(nil)+	missionControl.On("ReportPaymentSuccess",+		mock.Anything, mock.Anything,+	).Return(nil)++	// Mock SettleAttempt by changing one of the HTLCs to be settled.+	preimage := lntypes.Preimage{1, 2, 3}+	settledAttempt := makeSettledAttempt(+		int(paymentAmt/4), 0, preimage,+	)+	controlTower.On("SettleAttempt",+		identifier, mock.Anything, mock.Anything,+	).Return(&settledAttempt, nil).Run(func(args mock.Arguments) {+		// Whenever this method is invoked, we will mark the first+		// active attempt settled and exit.+		for i, attempt := range payment.HTLCs {+			if attempt.Settle == nil {+				attempt.Settle = &channeldb.HTLCSettleInfo{+					Preimage: preimage,+				}+				payment.HTLCs[i] = attempt+				return+			}+		}+	})++	// Call the actual method SendPayment on router. This is place inside a+	// goroutine so we can set a timeout for the whole test, in case+	// anything goes wrong and the test never finishes.+	done := make(chan struct{})+	var p lntypes.Hash+	go func() {+		p, _, err = router.SendPayment(req)+		close(done)+	}()++	select {+	case <-done:+	case <-time.After(testTimeout):+		t.Fatalf("SendPayment didn't exit")+	}++	// Finally, validate the returned values and check that the mock+	// methods are called as expected.+	require.NoError(t, err, "send payment failed")+	require.EqualValues(t, preimage, p, "preimage not match")++	// Note that we also implicitly check the methods such as FailAttempt,+	// ReportPaymentFail, etc, are not called because we never mocked them+	// in this test. If any of the unexpected methods was called, the test+	// would fail.+	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)+	sessionSource.AssertExpectations(t)+	session.AssertExpectations(t)+	missionControl.AssertExpectations(t)+}++// TestSendMPPaymentSucceedOnExtraShards tests that we need extra attempts if+// there are failed ones,so that a payment is successfully sent. This test+// mainly focuses on testing the logic of the method resumePayment is+// implemented as expected.+func TestSendMPPaymentSucceedOnExtraShards(t *testing.T) {+	const startingBlockHeight = 101++	// Create mockers to initialize the router.+	controlTower := &mockControlTower{}+	sessionSource := &mockPaymentSessionSource{}+	missionControl := &mockMissionControl{}+	payer := &mockPaymentAttemptDispatcher{}+	chain := newMockChain(startingBlockHeight)+	chainView := newMockChainView(chain)+	testGraph := createDummyTestGraph(t)++	// Define the behavior of the mockers to the point where we can+	// successfully start the router.+	controlTower.On("FetchInFlightPayments").Return(+		[]*channeldb.MPPayment{}, nil,+	)+	payer.On("CleanStore", mock.Anything).Return(nil)++	// Create and start the router.+	router, err := New(Config{+		Control:        controlTower,+		SessionSource:  sessionSource,+		MissionControl: missionControl,+		Payer:          payer,++		// TODO(yy): create new mocks for the chain and chainview.+		Chain:     chain,+		ChainView: chainView,++		// TODO(yy): mock the graph once it's changed into interface.+		Graph: testGraph.graph,++		Clock:              clock.NewTestClock(time.Unix(1, 0)),+		GraphPruneInterval: time.Hour * 2,+		NextPaymentID: func() (uint64, error) {+			next := atomic.AddUint64(&uniquePaymentID, 1)+			return next, nil+		},+	})+	require.NoError(t, err, "failed to create router")++	// Make sure the router can start and stop without error.+	require.NoError(t, router.Start(), "router failed to start")+	defer func() {+		require.NoError(t, router.Stop(), "router failed to stop")+	}()++	// Once the router is started, check that the mocked methods are called+	// as expected.+	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)++	// Mock the methods to the point where we are inside the function+	// resumePayment.+	paymentAmt := lnwire.MilliSatoshi(20000)+	req := createDummyLightningPayment(+		t, testGraph.aliasMap["c"], paymentAmt,+	)+	identifier := lntypes.Hash(req.Identifier())+	session := &mockPaymentSession{}+	sessionSource.On("NewPaymentSession", req).Return(session, nil)+	controlTower.On("InitPayment", identifier, mock.Anything).Return(nil)++	// The following mocked methods are called inside resumePayment. Note+	// that the payment object below will determine the state of the+	// paymentLifecycle.+	payment := &channeldb.MPPayment{}+	controlTower.On("FetchPayment", identifier).Return(payment, nil)++	// Create a route that can send 1/4 of the total amount. This value+	// will be returned by calling RequestRoute.+	shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap)+	require.NoError(t, err, "failed to create route")+	session.On("RequestRoute",+		mock.Anything, mock.Anything, mock.Anything, mock.Anything,+	).Return(shard, nil)++	// Make a new htlc attempt with zero fee and append it to the payment's+	// HTLCs when calling RegisterAttempt.+	activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0)+	controlTower.On("RegisterAttempt",+		identifier, mock.Anything,+	).Return(nil).Run(func(args mock.Arguments) {+		payment.HTLCs = append(payment.HTLCs, activeAttempt)+	})++	// Create a buffered chan and it will be returned by GetPaymentResult.+	payer.resultChan = make(chan *htlcswitch.PaymentResult, 10)++	// We use the failAttemptCount to track how many attempts we want to+	// fail. Each time the following mock method is called, the count gets+	// updated.+	failAttemptCount := 0+	payer.On("GetPaymentResult",+		mock.Anything, identifier, mock.Anything,+	).Run(func(args mock.Arguments) {+		// Before the mock method is returned, we send the result to+		// the read-only chan.++		// Update the counter.+		failAttemptCount++++		// We will make the first two attempts failed with temporary+		// error.+		if failAttemptCount <= 2 {+			payer.resultChan <- &htlcswitch.PaymentResult{+				Error: htlcswitch.NewForwardingError(+					&lnwire.FailTemporaryChannelFailure{},+					1,+				),+			}+			return+		}++		// Otherwise we will mark the attempt succeeded.+		payer.resultChan <- &htlcswitch.PaymentResult{}+	})++	// Mock the FailAttempt method to fail one of the attempts.+	var failedAttempt channeldb.HTLCAttempt+	controlTower.On("FailAttempt",+		identifier, mock.Anything, mock.Anything,+	).Return(&failedAttempt, nil).Run(func(args mock.Arguments) {+		// Whenever this method is invoked, we will mark the first+		// active attempt as failed and exit.+		for i, attempt := range payment.HTLCs {+			if attempt.Settle != nil || attempt.Failure != nil {+				continue+			}++			attempt.Failure = &channeldb.HTLCFailInfo{}+			failedAttempt = attempt+			payment.HTLCs[i] = attempt+			return+		}++	})++	// Setup ReportPaymentFail to return nil reason and error so the+	// payment won't fail.+	missionControl.On("ReportPaymentFail",+		mock.Anything, mock.Anything, mock.Anything, mock.Anything,+	).Return(nil, nil)++	// Simple mocking the rest.+	payer.On("SendHTLC",+		mock.Anything, mock.Anything, mock.Anything,+	).Return(nil)+	missionControl.On("ReportPaymentSuccess",+		mock.Anything, mock.Anything,+	).Return(nil)++	// Mock SettleAttempt by changing one of the HTLCs to be settled.+	preimage := lntypes.Preimage{1, 2, 3}+	settledAttempt := makeSettledAttempt(+		int(paymentAmt/4), 0, preimage,+	)+	controlTower.On("SettleAttempt",+		identifier, mock.Anything, mock.Anything,+	).Return(&settledAttempt, nil).Run(func(args mock.Arguments) {+		// Whenever this method is invoked, we will mark the first+		// active attempt settled and exit.+		for i, attempt := range payment.HTLCs {+			if attempt.Settle != nil || attempt.Failure != nil {+				continue+			}++			attempt.Settle = &channeldb.HTLCSettleInfo{+				Preimage: preimage,+			}+			payment.HTLCs[i] = attempt+			return+		}+	})++	// Call the actual method SendPayment on router. This is place inside a+	// goroutine so we can set a timeout for the whole test, in case+	// anything goes wrong and the test never finishes.+	done := make(chan struct{})+	var p lntypes.Hash+	go func() {+		p, _, err = router.SendPayment(req)+		close(done)+	}()++	select {+	case <-done:+	case <-time.After(testTimeout):+		t.Fatalf("SendPayment didn't exit")+	}++	// Finally, validate the returned values and check that the mock+	// methods are called as expected.+	require.NoError(t, err, "send payment failed")+	require.EqualValues(t, preimage, p, "preimage not match")++	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)+	sessionSource.AssertExpectations(t)+	session.AssertExpectations(t)+	missionControl.AssertExpectations(t)+}++// TestSendMPPaymentFailed tests that when one of the shard fails with a+// terminal error, the router will stop attempting and the payment will fail.+// This test mainly focuses on testing the logic of the method resumePayment+// is implemented as expected.+func TestSendMPPaymentFailed(t *testing.T) {+	const startingBlockHeight = 101++	// Create mockers to initialize the router.+	controlTower := &mockControlTower{}+	sessionSource := &mockPaymentSessionSource{}+	missionControl := &mockMissionControl{}+	payer := &mockPaymentAttemptDispatcher{}+	chain := newMockChain(startingBlockHeight)+	chainView := newMockChainView(chain)+	testGraph := createDummyTestGraph(t)++	// Define the behavior of the mockers to the point where we can+	// successfully start the router.+	controlTower.On("FetchInFlightPayments").Return(+		[]*channeldb.MPPayment{}, nil,+	)+	payer.On("CleanStore", mock.Anything).Return(nil)++	// Create and start the router.+	router, err := New(Config{+		Control:        controlTower,+		SessionSource:  sessionSource,+		MissionControl: missionControl,+		Payer:          payer,++		// TODO(yy): create new mocks for the chain and chainview.+		Chain:     chain,+		ChainView: chainView,++		// TODO(yy): mock the graph once it's changed into interface.+		Graph: testGraph.graph,++		Clock:              clock.NewTestClock(time.Unix(1, 0)),+		GraphPruneInterval: time.Hour * 2,+		NextPaymentID: func() (uint64, error) {+			next := atomic.AddUint64(&uniquePaymentID, 1)+			return next, nil+		},+	})+	require.NoError(t, err, "failed to create router")++	// Make sure the router can start and stop without error.+	require.NoError(t, router.Start(), "router failed to start")+	defer func() {+		require.NoError(t, router.Stop(), "router failed to stop")+	}()++	// Once the router is started, check that the mocked methods are called+	// as expected.+	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)++	// Mock the methods to the point where we are inside the function+	// resumePayment.+	paymentAmt := lnwire.MilliSatoshi(10000)+	req := createDummyLightningPayment(+		t, testGraph.aliasMap["c"], paymentAmt,+	)+	identifier := lntypes.Hash(req.Identifier())+	session := &mockPaymentSession{}+	sessionSource.On("NewPaymentSession", req).Return(session, nil)+	controlTower.On("InitPayment", identifier, mock.Anything).Return(nil)++	// The following mocked methods are called inside resumePayment. Note+	// that the payment object below will determine the state of the+	// paymentLifecycle.+	payment := &channeldb.MPPayment{}+	controlTower.On("FetchPayment", identifier).Return(payment, nil)++	// Create a route that can send 1/4 of the total amount. This value+	// will be returned by calling RequestRoute.+	shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap)+	require.NoError(t, err, "failed to create route")+	session.On("RequestRoute",+		mock.Anything, mock.Anything, mock.Anything, mock.Anything,+	).Return(shard, nil)++	// Make a new htlc attempt with zero fee and append it to the payment's+	// HTLCs when calling RegisterAttempt.+	activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0)+	controlTower.On("RegisterAttempt",+		identifier, mock.Anything,+	).Return(nil).Run(func(args mock.Arguments) {+		payment.HTLCs = append(payment.HTLCs, activeAttempt)+	})++	// Create a buffered chan and it will be returned by GetPaymentResult.+	payer.resultChan = make(chan *htlcswitch.PaymentResult, 10)++	// We use the failAttemptCount to track how many attempts we want to+	// fail. Each time the following mock method is called, the count gets+	// updated.+	failAttemptCount := 0+	payer.On("GetPaymentResult",+		mock.Anything, identifier, mock.Anything,+	).Run(func(args mock.Arguments) {+		// Before the mock method is returned, we send the result to+		// the read-only chan.++		// Update the counter.+		failAttemptCount++++		// We fail the first attempt with terminal error.+		if failAttemptCount == 1 {+			payer.resultChan <- &htlcswitch.PaymentResult{+				Error: htlcswitch.NewForwardingError(+					&lnwire.FailIncorrectDetails{},+					1,+				),+			}+			return++		}++		// We will make the rest attempts failed with temporary error.+		payer.resultChan <- &htlcswitch.PaymentResult{+			Error: htlcswitch.NewForwardingError(+				&lnwire.FailTemporaryChannelFailure{},+				1,+			),+		}+	})++	// Mock the FailAttempt method to fail one of the attempts.+	var failedAttempt channeldb.HTLCAttempt+	controlTower.On("FailAttempt",+		identifier, mock.Anything, mock.Anything,+	).Return(&failedAttempt, nil).Run(func(args mock.Arguments) {+		// Whenever this method is invoked, we will mark the first+		// active attempt as failed and exit.+		for i, attempt := range payment.HTLCs {+			if attempt.Settle != nil || attempt.Failure != nil {+				continue+			}++			attempt.Failure = &channeldb.HTLCFailInfo{}+			failedAttempt = attempt+			payment.HTLCs[i] = attempt+			return+		}++	})++	// Setup ReportPaymentFail to return nil reason and error so the+	// payment won't fail.+	var called bool+	failureReason := channeldb.FailureReasonPaymentDetails+	missionControl.On("ReportPaymentFail",+		mock.Anything, mock.Anything, mock.Anything, mock.Anything,+	).Return(nil, nil).Run(func(args mock.Arguments) {+		// We only return the terminal error once, thus when the method+		// is called, we will return it with a nil error.+		if called {+			missionControl.failReason = nil+			return+		}++		// If it's the first time calling this method, we will return a+		// terminal error.+		missionControl.failReason = &failureReason+		payment.FailureReason = &failureReason+		called = true+	})++	// Simple mocking the rest.+	controlTower.On("Fail", identifier, failureReason).Return(nil)+	payer.On("SendHTLC",+		mock.Anything, mock.Anything, mock.Anything,+	).Return(nil)++	// Call the actual method SendPayment on router. This is place inside a+	// goroutine so we can set a timeout for the whole test, in case+	// anything goes wrong and the test never finishes.+	done := make(chan struct{})+	var p lntypes.Hash+	go func() {+		p, _, err = router.SendPayment(req)+		close(done)+	}()++	select {+	case <-done:+	case <-time.After(testTimeout):+		t.Fatalf("SendPayment didn't exit")+	}++	// Finally, validate the returned values and check that the mock+	// methods are called as expected.+	require.Error(t, err, "expected send payment error")+	require.EqualValues(t, [32]byte{}, p, "preimage not match")++	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)+	sessionSource.AssertExpectations(t)+	session.AssertExpectations(t)+	missionControl.AssertExpectations(t)+}++// TestSendMPPaymentFailedWithShardsInFlight tests that when the payment is in+// terminal state, even if we have shards in flight, we still fail the payment+// and exit. This test mainly focuses on testing the logic of the method+// resumePayment is implemented as expected.+func TestSendMPPaymentFailedWithShardsInFlight(t *testing.T) {+	const startingBlockHeight = 101++	// Create mockers to initialize the router.+	controlTower := &mockControlTower{}+	sessionSource := &mockPaymentSessionSource{}+	missionControl := &mockMissionControl{}+	payer := &mockPaymentAttemptDispatcher{}+	chain := newMockChain(startingBlockHeight)+	chainView := newMockChainView(chain)+	testGraph := createDummyTestGraph(t)++	// Define the behavior of the mockers to the point where we can+	// successfully start the router.+	controlTower.On("FetchInFlightPayments").Return(+		[]*channeldb.MPPayment{}, nil,+	)+	payer.On("CleanStore", mock.Anything).Return(nil)++	// Create and start the router.+	router, err := New(Config{+		Control:        controlTower,+		SessionSource:  sessionSource,+		MissionControl: missionControl,+		Payer:          payer,++		// TODO(yy): create new mocks for the chain and chainview.+		Chain:     chain,+		ChainView: chainView,++		// TODO(yy): mock the graph once it's changed into interface.+		Graph: testGraph.graph,++		Clock:              clock.NewTestClock(time.Unix(1, 0)),+		GraphPruneInterval: time.Hour * 2,+		NextPaymentID: func() (uint64, error) {+			next := atomic.AddUint64(&uniquePaymentID, 1)+			return next, nil+		},+	})+	require.NoError(t, err, "failed to create router")++	// Make sure the router can start and stop without error.+	require.NoError(t, router.Start(), "router failed to start")+	defer func() {+		require.NoError(t, router.Stop(), "router failed to stop")+	}()++	// Once the router is started, check that the mocked methods are called+	// as expected.+	controlTower.AssertExpectations(t)+	payer.AssertExpectations(t)++	// Mock the methods to the point where we are inside the function+	// resumePayment.+	paymentAmt := lnwire.MilliSatoshi(10000)+	req := createDummyLightningPayment(+		t, testGraph.aliasMap["c"], paymentAmt,+	)+	identifier := lntypes.Hash(req.Identifier())+	session := &mockPaymentSession{}+	sessionSource.On("NewPaymentSession", req).Return(session, nil)+	controlTower.On("InitPayment", identifier, mock.Anything).Return(nil)++	// The following mocked methods are called inside resumePayment. Note+	// that the payment object below will determine the state of the+	// paymentLifecycle.+	payment := &channeldb.MPPayment{}+	controlTower.On("FetchPayment", identifier).Return(payment, nil)++	// Create a route that can send 1/4 of the total amount. This value+	// will be returned by calling RequestRoute.+	shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap)+	require.NoError(t, err, "failed to create route")+	session.On("RequestRoute",+		mock.Anything, mock.Anything, mock.Anything, mock.Anything,+	).Return(shard, nil)++	// Make a new htlc attempt with zero fee and append it to the payment's+	// HTLCs when calling RegisterAttempt.+	activeAttempt := makeActiveAttempt(int(paymentAmt/4), 0)+	controlTower.On("RegisterAttempt",+		identifier, mock.Anything,+	).Return(nil).Run(func(args mock.Arguments) {+		payment.HTLCs = append(payment.HTLCs, activeAttempt)+	})++	// Create a buffered chan and it will be returned by GetPaymentResult.+	payer.resultChan = make(chan *htlcswitch.PaymentResult, 10)++	// We use the failAttemptCount to track how many attempts we want to+	// fail. Each time the following mock method is called, the count gets+	// updated.+	failAttemptCount := 0+	payer.On("GetPaymentResult",+		mock.Anything, identifier, mock.Anything,+	).Run(func(args mock.Arguments) {+		// Before the mock method is returned, we send the result to+		// the read-only chan.++		// Update the counter.+		failAttemptCount++++		// We fail the first attempt with terminal error.+		if failAttemptCount == 1 {+			payer.resultChan <- &htlcswitch.PaymentResult{+				Error: htlcswitch.NewForwardingError(+					&lnwire.FailIncorrectDetails{},+					1,+				),+			}+			return++		}++		// For the rest attempts we will NOT send anything to the+		// resultChan, thus making all the shards in active state,+		// neither settled or failed.+	})++	// Mock the FailAttempt method to fail EXACTLY once.+	var failedAttempt channeldb.HTLCAttempt+	controlTower.On("FailAttempt",+		identifier, mock.Anything, mock.Anything,+	).Return(&failedAttempt, nil).Run(func(args mock.Arguments) {

Interesting alternative to the way we typically do things (sort of create the mocks as normal struct and "re-implement" any logic not able to be mocked out cleanly). This route sort of clutters the call site in the tests (imo), but as you mentioned earlier lets us more directly assert the control flow based on our "ideal mental model".

yyforyongyu

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 type paymentState struct { 	numShardsInFlight int 	remainingAmt      lnwire.MilliSatoshi 	remainingFees     lnwire.MilliSatoshi-	terminate         bool++	// terminate indicates the payment is in its final stage and no more+	// shards should be launched. This value is true if we have an HTLC+	// settled or the payment has an error.+	terminate bool+}++// terminated returns a bool to indicate there are no further actions needed+// and we should return what we have, either the payment preimage or the+// payment error.+func (ps paymentState) terminated() bool {+	// If the payment is in final stage and we have no in flight shards to+	// wait result for, we consider the whole action terminated.+	return ps.terminate && ps.numShardsInFlight == 0+}++// needWaitForShards returns a bool to specify whether we need to wait for the+// outcome of the shanrdHandler.+func (ps paymentState) needWaitForShards() bool {+	// If we have in flight shards and the payment is in final stage, we+	// need to wait for the outcomes from the shards. Or if we have no more+	// money to be sent, we need to wait for the already launched shards.+	if ps.numShardsInFlight == 0 {

Does this represent a bug fix as the existing switch statement didn't exactly account for this?

(still getting through the diff)

yyforyongyu

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 type paymentState struct { 	numShardsInFlight int 	remainingAmt      lnwire.MilliSatoshi 	remainingFees     lnwire.MilliSatoshi-	terminate         bool++	// terminate indicates the payment is in its final stage and no more+	// shards should be launched. This value is true if we have an HTLC+	// settled or the payment has an error.+	terminate bool+}++// terminated returns a bool to indicate there are no further actions needed+// and we should return what we have, either the payment preimage or the+// payment error.+func (ps paymentState) terminated() bool {+	// If the payment is in final stage and we have no in flight shards to+	// wait result for, we consider the whole action terminated.+	return ps.terminate && ps.numShardsInFlight == 0+}++// needWaitForShards returns a bool to specify whether we need to wait for the+// outcome of the shanrdHandler.+func (ps paymentState) needWaitForShards() bool {+	// If we have in flight shards and the payment is in final stage, we+	// need to wait for the outcomes from the shards. Or if we have no more+	// money to be sent, we need to wait for the already launched shards.+	if ps.numShardsInFlight == 0 {+		return false+	}+	return ps.terminate || ps.remainingAmt == 0 } -// paymentState uses the passed payment to find the latest information we need-// to act on every iteration of the payment loop.-func (p *paymentLifecycle) paymentState(payment *channeldb.MPPayment) (+// updatePaymentState will fetch db for the payment to find the latest+// information we need to act on every iteration of the payment loop and update+// the paymentState.+func (p *paymentLifecycle) updatePaymentState() (*channeldb.MPPayment,

updatePaymentState makes it semes like we're mutating the state on disk. How about fetchPaymentState instead?

Also some small grammatical changes to the comment:

updatePaymentState will query the db for the latest payment state information we need to act on every iteration of the payment loop and update the paymentState.

yyforyongyu

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 lifecycle:  		// If this route will consume the last remeining amount to send 		// to the receiver, this will be our last shard (for now).-		lastShard := rt.ReceiverAmt() == state.remainingAmt+		lastShard := rt.ReceiverAmt() == currentState.remainingAmt  		// We found a route to try, launch a new shard. 		attempt, outcome, err := shardHandler.launchShard(rt, lastShard)-		switch {-		// We may get a terminal error if we've processed a shard with-		// a terminal state (settled or permanent failure), while we-		// were pathfinding. We know we're in a terminal state here,-		// so we can continue and wait for our last shards to return.-		case err == channeldb.ErrPaymentTerminal:

Why don't we need to handle this terminal payment state any longer?

yyforyongyu

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 func (p *shardHandler) collectResultAsync(attempt *channeldb.HTLCAttemptInfo) { 					attempt.AttemptID, p.identifier, err) 			} -			select {-			case p.shardErrors <- err:-			case <-p.router.quit:-			case <-p.quit:-			}+			// Overwrite errToSend and return.

May be worth mentioning here (to make the control flow clearer) that we're just setting the "return param" for the defer above (handleResultErr).

yyforyongyu

comment created time in 3 hours

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 func (m *mockControlTowerOld) SubscribePayment(paymentHash lntypes.Hash) (  	return nil, errors.New("not implemented") }++type mockPaymentAttemptDispatcher struct {

Nice move re renaming the older versions to keep things in place and create a new base test abstraction for any future changes!

yyforyongyu

comment created time in a day

Pull request review commentlightningnetwork/lnd

routing: fix payment state and refactor payment lifecycle tests

 func (p *shardHandler) collectResultAsync(attempt *channeldb.HTLCAttemptInfo) { 					attempt.AttemptID, p.identifier, err) 			} -			select {-			case p.shardErrors <- err:

Nice usage of the defer here to get rid of that duplication!

yyforyongyu

comment created time in 3 hours

issue commentlightningnetwork/lnd

Recovery window failing to detect transaction to same address as one it has detected

How would I ascertain the wallet birthday, either from files in the datadir or lncli?

ProofOfKeags

comment created time in 4 hours

pull request commentlightningnetwork/lnd

lnd: only set payment address if not empty in PaymentRequest

I don't see how this wasn't already covered, given the request is identical to the proto sample you posted in the original issue.

Ah I think the difference here is all our itests use SendPaymentV2 and not the deprecated variant on the main Lightning service.

bjarnemagnussen

comment created time in 4 hours

Pull request review commentlightningnetwork/lnd

lnd: only set payment address if not empty in PaymentRequest

 func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPayme 		return payIntent, errors.New("invalid payment address length") 	} -	if payIntent.paymentAddr == nil {+	// Set the payment address if it was explicitly defined with the+	// rpcPaymentRequest.+	// Note that the payment address for the payIntent should be nil if none+	// was provided with the rpcPaymentRequest.+	if len(rpcPayReq.PaymentAddr) != 0 { 		payIntent.paymentAddr = &[32]byte{}+		copy(payIntent.paymentAddr[:], rpcPayReq.PaymentAddr) 	}-	copy(payIntent.paymentAddr[:], rpcPayReq.PaymentAddr)

Ahh, so this ended up copying a zero valued payment address, which was rejected as it's used as a shibboleth elsewhere in the codebase.

bjarnemagnussen

comment created time in 4 hours

Pull request review commentbitcoin/bitcoin

log: Mitigate disk filling attacks by rate limiting LogPrintf

 namespace BCLog {     } } -void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line)+static constexpr uint64_t HOURLY_LOG_QUOTA_IN_BYTES_PER_SOURCE_LOCATION{1024 * 1024};++bool BCLog::Logger::RateLimit(std::string& str, const std::string& logging_function, const SourceLocation& source_location)+{+    if (!m_rate_limiting) {+        // Rate limiting is disabled.+        return false;+    }++    const std::chrono::seconds now = GetTime<std::chrono::seconds>();+    QuotaUsage& quota_usage = m_quota_usage_per_source_location[source_location];+    // Is the quota exceeded before this log call?+    bool quota_exceeded_before = quota_usage.m_bytes_logged > HOURLY_LOG_QUOTA_IN_BYTES_PER_SOURCE_LOCATION;++    bool dont_skip = false;

That is correct! But this does unfortunately not work because we hold a lock here https://github.com/bitcoin/bitcoin/blob/a2916ae5043436d3fd22acb44c5663227fa7eb90/src/logging.cpp#L317

A recursive call to LogPrintf also feels a bit dangerous to me.

dergoegge

comment created time in 4 hours

push eventlightningnetwork/lnd

Oliver Gugger

commit sha 2e9dd0bcf2bce9ba226301391a3ed061d8038a53

lnrpc+rpcserver: allow abandonchannel to be used in regular build An often requested feature is to use the abandonchannel API in regular builds and not only dev builds to get rid of stuck channels that had their funding transaction invalidated. The initial reason for putting the call behind the build flag was a safety concern to make sure nobody uses this on active channels by accident.

view details

Oliver Gugger

commit sha 3b712bf7221f350c266b931355afe317febca1df

lncli: add i_know_what_i_am_doing flag to abandonchannel

view details

Olaoluwa Osuntokun

commit sha 1287328678c2c6c31792287bb413d46714af0c9c

Merge pull request #5335 from guggero/abandonchannel-no-dev RPC/CLI: Allow abandonchannel to be used in regular build

view details

push time in 4 hours

PR merged lightningnetwork/lnd

RPC/CLI: Allow abandonchannel to be used in regular build channels rpc

An often requested feature is to use the abandonchannel API in regular builds and not only dev builds to get rid of stuck channels that had their funding transaction invalidated. The initial reason for putting the call behind the build flag was a safety concern to make sure nobody uses this on active channels by accident.

+753 -703

1 comment

5 changed files

guggero

pr closed time in 4 hours

Pull request review commentlightningnetwork/lnd

multi: set zero bandwidth hint for channels that do not have any available slots

 type ChannelLink interface { 	// will use this function in forwarding decisions accordingly. 	EligibleToForward() bool +	// MayAddOutgoingHtlc returns an error if we may not add an outgoing

This endless storm of htlcs happens in the following case:

Ah yeh this makes more sense, thanks for the breakdown.

The alternative would be to update handleSendError's error processing to specifically understand this type of switch error and report it to mission control differently, since right now we're just logging i

Don't think this is the correct route either as we'd end up "penalizing" our local channels using our existing observation system when we we're actually able to have an up-to-date view of the state since it's a local channel.

The thing that made be to a double take was the fact that we're extending a fundamental interface in the switch with a method that was effectively only put in place to solve a one-off issue. However looking at this addition from another angle, it forces callers that handle a link to be aware of that fact that we actually have two constraints w.r.t being able to forward HTLCs: the set of available bandwidth, and the current flow control constraints.

With that said, how about renaming the newly added method from MayAddOutgoingHtlc to something like func PaymentSlotAvailable(amt) bool (just a suggestion)? This reflects that the method is a best-effort attempt at claiming an available payment slots (which encapsulates things like the future dust limits, max htlc, max in flight, etc). It's best-effort as no strong guarantees are made as it's possible that a forwarded HTLC instead claims the slots, and the caller would need to be aware of that. With this interface change, we'd also start to thread through the amount as then we ensure we're able to factor in all the other flow control constraints. Actually without this, I think other infinite loops exist where adding an HTLC violates another constraint (aside from max HTLCs).

Doesn't look like we have the amount available here when we go to query for bandwidth hints, but with a small tweak we could have the bandwidthHintsMap map to a function closure (or interface) to allow it to accept an amount (and possibly later other parmaters). Looking at this section of the codebase with fresh eyes, it doesn't look like we attempt to adhere to the link level constraints enforced by the remote party w.r.t what type of HTLCs they'll accept (like the link level min HTLC param). Taking this final step to make the bandwidth hints (from the PoV of the router) aware (via direction) of these link level constraints should address this gap and any other lingering ones.

carlaKC

comment created time in 4 hours

pull request commentbitcoin/bitcoin

Add OutputType::BECH32M and related wallet support for fetching bech32m addresses

re-ACK 754f134a50cc56cdf0baf996d909c992770fcc97

Confirmed only changes were rebasing and fixing wallet_taproot.py.

achow101

comment created time in 4 hours

pull request commentbitcoin/bitcoin

Add OutputType::BECH32M and related wallet support for fetching bech32m addresses

When should bech32m be added to the -addresstype and -changetype wallet config option helps?

When we make bech32m descriptors by default.

achow101

comment created time in 4 hours

Pull request review commentbitcoin/bitcoin

log: Mitigate disk filling attacks by rate limiting LogPrintf

 void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& loggi     for (const auto& cb : m_print_callbacks) {         cb(str_prefixed);     }-    if (m_print_to_file) {+    if (m_print_to_file && !skip_writing_to_disk_due_to_rate_limiting) {

We want the rate limiting messages like "restarting logging from..." to also be printed to the console, so we have to call RateLimit before that and store the result. I am still gonna change the name of skip_writing_to_disk_due_to_rate_limiting because its a bit long.

dergoegge

comment created time in 4 hours