mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-18 13:09:08 +02:00
Add pay offer dialog and backend method (#296)
* Add insert sent payment method * Delete db container from itest * Add other container in itest * Connect to other squeak node in itest * Use client lightning container for itest to get offers from main node * Get offers itest working * Open channel to buy offer in itest * Successfully pay offer * Remove old print statements from itest * Successfully unlock squeak in pay offer method * Assert that decrypted content is correct in pay offer itest
This commit is contained in:
parent
e9cfcd00c9
commit
8ebdc754ca
15 changed files with 510 additions and 13 deletions
|
|
@ -0,0 +1,181 @@
|
|||
import React, {useState, useEffect} from 'react';
|
||||
import {
|
||||
Paper,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Typography,
|
||||
Grid,
|
||||
Box,
|
||||
Link,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
TextField,
|
||||
DialogActions,
|
||||
Button,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
} from "@material-ui/core";
|
||||
import { MoreVert as MoreIcon } from "@material-ui/icons";
|
||||
import {useHistory} from "react-router-dom";
|
||||
import classnames from "classnames";
|
||||
|
||||
// styles
|
||||
import useStyles from "./styles";
|
||||
|
||||
import Widget from "../../components/Widget";
|
||||
import SqueakThreadItem from "../../components/SqueakThreadItem";
|
||||
|
||||
import {
|
||||
CloseChannelRequest,
|
||||
ChannelPoint,
|
||||
} from "../../proto/lnd_pb"
|
||||
import { client } from "../../squeakclient/squeakclient"
|
||||
|
||||
|
||||
export default function CloseChannelDialog({
|
||||
open,
|
||||
txId,
|
||||
outputIndex,
|
||||
handleClose,
|
||||
...props
|
||||
}) {
|
||||
var classes = useStyles();
|
||||
const history = useHistory();
|
||||
|
||||
var [amount, setAmount] = useState(0);
|
||||
|
||||
const resetFields = () => {
|
||||
setAmount(0);
|
||||
};
|
||||
|
||||
const handleChangeAmount = (event) => {
|
||||
setAmount(event.target.value);
|
||||
};
|
||||
|
||||
const closeChannel = (txId, outputIndex) => {
|
||||
console.log("called closeChannel");
|
||||
|
||||
var closeChannelRequest = new CloseChannelRequest()
|
||||
var channelPoint = new ChannelPoint();
|
||||
channelPoint.setFundingTxidStr(txId);
|
||||
channelPoint.setOutputIndex(outputIndex);
|
||||
closeChannelRequest.setChannelPoint(channelPoint);
|
||||
console.log(closeChannelRequest);
|
||||
|
||||
client.lndCloseChannel(closeChannelRequest, {}, (err, response) => {
|
||||
if (err) {
|
||||
console.log(err.message);
|
||||
alert('Error closing channel: ' + err.message);
|
||||
return;
|
||||
}
|
||||
console.log(response);
|
||||
// goToProfilePage(response.getProfileId());
|
||||
});
|
||||
};
|
||||
|
||||
// const goToProfilePage = (profileId) => {
|
||||
// history.push("/app/profile/" + profileId);
|
||||
// };
|
||||
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
console.log( 'txId:', txId);
|
||||
console.log( 'outputIndex:', outputIndex);
|
||||
closeChannel(txId, outputIndex);
|
||||
handleClose();
|
||||
}
|
||||
|
||||
function TxIdInput() {
|
||||
return (
|
||||
<TextField
|
||||
id="txid-textarea"
|
||||
label="TxId"
|
||||
required
|
||||
autoFocus
|
||||
value={txId}
|
||||
fullWidth
|
||||
inputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function OutputIndexInput() {
|
||||
return (
|
||||
<TextField
|
||||
id="outputindex-textarea"
|
||||
label="Output Index"
|
||||
required
|
||||
autoFocus
|
||||
value={outputIndex}
|
||||
fullWidth
|
||||
inputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function LocalFundingAmountInput() {
|
||||
return (
|
||||
<TextField
|
||||
id="amount-textarea"
|
||||
label="Local Funding Amount"
|
||||
required
|
||||
autoFocus
|
||||
value={amount}
|
||||
onChange={handleChangeAmount}
|
||||
fullWidth
|
||||
inputProps={{ maxLength: 64 }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CancelButton() {
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
function CloseChannelButton() {
|
||||
return (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.button}
|
||||
>
|
||||
Close Channel
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onEnter={resetFields} onClose={handleClose} aria-labelledby="form-dialog-title">
|
||||
<DialogTitle id="form-dialog-title">Close Channel</DialogTitle>
|
||||
<form className={classes.root} onSubmit={handleSubmit} noValidate autoComplete="off">
|
||||
<DialogContent>
|
||||
{TxIdInput()}
|
||||
</DialogContent>
|
||||
<DialogContent>
|
||||
{OutputIndexInput()}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{CancelButton()}
|
||||
{CloseChannelButton()}
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "BuyOfferDialog",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "BuyOfferDialog.js"
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import { makeStyles } from "@material-ui/styles";
|
||||
|
||||
export default makeStyles(theme => ({
|
||||
widgetWrapper: {
|
||||
display: "flex",
|
||||
minHeight: "100%",
|
||||
},
|
||||
widgetHeader: {
|
||||
padding: theme.spacing(3),
|
||||
paddingBottom: theme.spacing(1),
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
widgetRoot: {
|
||||
boxShadow: theme.customShadows.widget,
|
||||
},
|
||||
widgetBody: {
|
||||
paddingBottom: theme.spacing(3),
|
||||
paddingRight: theme.spacing(3),
|
||||
paddingLeft: theme.spacing(3),
|
||||
},
|
||||
noPadding: {
|
||||
padding: 0,
|
||||
},
|
||||
paper: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flexGrow: 1,
|
||||
overflow: "hidden",
|
||||
},
|
||||
moreButton: {
|
||||
margin: -theme.spacing(1),
|
||||
padding: 0,
|
||||
width: 40,
|
||||
height: 40,
|
||||
color: theme.palette.text.hint,
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: "rgba(255, 255, 255, 0.35)",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
@ -1,16 +1,6 @@
|
|||
version: '3'
|
||||
services:
|
||||
|
||||
db:
|
||||
image: postgres
|
||||
container_name: test_db
|
||||
environment:
|
||||
- POSTGRES_DB=postgres
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
volumes:
|
||||
- ../createdb.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
|
||||
btcd:
|
||||
image: btcd
|
||||
container_name: test_btcd
|
||||
|
|
@ -93,8 +83,23 @@ services:
|
|||
links:
|
||||
- "btcd:btcd"
|
||||
- "lnd_server:lnd"
|
||||
depends_on:
|
||||
- db
|
||||
sysctls:
|
||||
- net.ipv6.conf.all.disable_ipv6=0
|
||||
entrypoint: ["./start-sqkserver.sh"]
|
||||
|
||||
sqkserver_other:
|
||||
image: sqkserver
|
||||
container_name: test_sqkserver_other
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: docker/sqkserver/Dockerfile
|
||||
volumes:
|
||||
- test_shared:/rpc
|
||||
- test_lnd_client_dir:/root/.lnd
|
||||
- ./config.ini:/app/config.ini
|
||||
links:
|
||||
- "btcd:btcd"
|
||||
- "lnd_client:lnd"
|
||||
sysctls:
|
||||
- net.ipv6.conf.all.disable_ipv6=0
|
||||
entrypoint: ["./start-sqkserver.sh"]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function mine_blocks {
|
|||
|
||||
|
||||
cd itests
|
||||
docker-compose down --volumes
|
||||
docker-compose down --volumes --remove-orphans
|
||||
COMPOSE_DOCKER_CLI_BUILD=1 docker-compose build
|
||||
docker-compose up -d
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,24 @@ def server_stub():
|
|||
yield squeak_server_pb2_grpc.SqueakServerStub(server_channel)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def other_server_stub():
|
||||
with grpc.insecure_channel("sqkserver_other:8774") as server_channel:
|
||||
yield squeak_server_pb2_grpc.SqueakServerStub(server_channel)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def admin_stub():
|
||||
with grpc.insecure_channel("sqkserver:8994") as admin_channel:
|
||||
yield squeak_admin_pb2_grpc.SqueakAdminStub(admin_channel)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def other_admin_stub():
|
||||
with grpc.insecure_channel("sqkserver_other:8994") as admin_channel:
|
||||
yield squeak_admin_pb2_grpc.SqueakAdminStub(admin_channel)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def lightning_client():
|
||||
return load_lightning_client()
|
||||
|
|
|
|||
|
|
@ -778,3 +778,105 @@ def test_open_channel(server_stub, admin_stub, lightning_client, saved_squeak_ha
|
|||
|
||||
list_channels_response = admin_stub.LndListChannels(ln.ListChannelsRequest())
|
||||
assert len(list_channels_response.channels) == 0
|
||||
|
||||
|
||||
def test_connect_other_node(server_stub, admin_stub, other_server_stub, other_admin_stub, lightning_client, signing_profile_id, saved_squeak_hash):
|
||||
# Get all squeak displays
|
||||
get_followed_squeak_display_response = other_admin_stub.GetFollowedSqueakDisplays(
|
||||
squeak_admin_pb2.GetFollowedSqueakDisplaysRequest()
|
||||
)
|
||||
assert len(get_followed_squeak_display_response.squeak_display_entries) == 0
|
||||
|
||||
# Add the main node as a peer
|
||||
create_peer_response = other_admin_stub.CreatePeer(
|
||||
squeak_admin_pb2.CreatePeerRequest(
|
||||
host="sqkserver",
|
||||
port=8774,
|
||||
)
|
||||
)
|
||||
peer_id = create_peer_response.peer_id
|
||||
|
||||
# Set the peer to be downloading
|
||||
other_admin_stub.SetPeerDownloading(
|
||||
squeak_admin_pb2.SetPeerDownloadingRequest(
|
||||
peer_id=peer_id,
|
||||
downloading=True,
|
||||
)
|
||||
)
|
||||
|
||||
# Get the squeak profile
|
||||
get_squeak_profile_response = admin_stub.GetSqueakProfile(
|
||||
squeak_admin_pb2.GetSqueakProfileRequest(
|
||||
profile_id=signing_profile_id,
|
||||
)
|
||||
)
|
||||
squeak_profile_address = get_squeak_profile_response.squeak_profile.address
|
||||
squeak_profile_name = get_squeak_profile_response.squeak_profile.profile_name
|
||||
print("Got squeak profile: {} with address: {}".format(squeak_profile_name, squeak_profile_address))
|
||||
|
||||
|
||||
# Set the signing profile to be sharing on the main server
|
||||
admin_stub.SetSqueakProfileSharing(
|
||||
squeak_admin_pb2.SetSqueakProfileSharingRequest(
|
||||
profile_id=signing_profile_id,
|
||||
sharing=True,
|
||||
)
|
||||
)
|
||||
|
||||
# Add the contact profile to the other server and set the profile to be following
|
||||
create_contact_profile_response = other_admin_stub.CreateContactProfile(
|
||||
squeak_admin_pb2.CreateContactProfileRequest(
|
||||
profile_name=squeak_profile_name,
|
||||
address=squeak_profile_address,
|
||||
)
|
||||
)
|
||||
contact_profile_id = create_contact_profile_response.profile_id
|
||||
other_admin_stub.SetSqueakProfileFollowing(
|
||||
squeak_admin_pb2.SetSqueakProfileFollowingRequest(
|
||||
profile_id=contact_profile_id,
|
||||
following=True,
|
||||
)
|
||||
)
|
||||
|
||||
# Sync squeaks
|
||||
other_admin_stub.SyncSqueaks(
|
||||
squeak_admin_pb2.SyncSqueaksRequest(),
|
||||
)
|
||||
time.sleep(10)
|
||||
|
||||
# Get the buy offer
|
||||
get_buy_offers_response = other_admin_stub.GetBuyOffers(
|
||||
squeak_admin_pb2.GetBuyOffersRequest(
|
||||
squeak_hash=saved_squeak_hash.hex(),
|
||||
)
|
||||
)
|
||||
print(get_buy_offers_response)
|
||||
assert len(get_buy_offers_response.offers) > 0
|
||||
|
||||
offer = get_buy_offers_response.offers[0]
|
||||
|
||||
with connect_peer(lightning_client, offer.node_host, offer.node_pubkey), \
|
||||
open_channel(lightning_client, offer.node_pubkey, 1000000):
|
||||
|
||||
list_channels_response = lightning_client.list_channels()
|
||||
print(list_channels_response)
|
||||
|
||||
# Pay the offer
|
||||
pay_offer_response = other_admin_stub.PayOffer(
|
||||
squeak_admin_pb2.PayOfferRequest(
|
||||
offer_id=offer.offer_id,
|
||||
)
|
||||
)
|
||||
print(pay_offer_response)
|
||||
assert pay_offer_response.sent_payment_id > 0
|
||||
|
||||
# Get the squeak display item
|
||||
get_squeak_display_response = other_admin_stub.GetSqueakDisplay(
|
||||
squeak_admin_pb2.GetSqueakDisplayRequest(
|
||||
squeak_hash=saved_squeak_hash.hex(),
|
||||
)
|
||||
)
|
||||
assert (
|
||||
get_squeak_display_response.squeak_display_entry.content_str
|
||||
== "Hello from the profile on the server!"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -156,6 +156,14 @@ service SqueakAdmin {
|
|||
*/
|
||||
rpc GetBuyOffer (GetBuyOfferRequest) returns (GetBuyOfferReply) {}
|
||||
|
||||
/** sqkadmin: `syncsqueaks`
|
||||
*/
|
||||
rpc SyncSqueaks (SyncSqueaksRequest) returns (SyncSqueaksReply) {}
|
||||
|
||||
/** sqkadmin: `payoffer`
|
||||
*/
|
||||
rpc PayOffer (PayOfferRequest) returns (PayOfferReply) {}
|
||||
|
||||
}
|
||||
|
||||
message CreateSigningProfileRequest {
|
||||
|
|
@ -515,3 +523,19 @@ message OfferDisplayEntry {
|
|||
/// The invoice expiry
|
||||
int32 invoice_expiry = 9;
|
||||
}
|
||||
|
||||
message SyncSqueaksRequest {
|
||||
}
|
||||
|
||||
message SyncSqueaksReply {
|
||||
}
|
||||
|
||||
message PayOfferRequest {
|
||||
/// Offer id
|
||||
int32 offer_id = 1;
|
||||
}
|
||||
|
||||
message PayOfferReply {
|
||||
/// Sent payment id
|
||||
int32 sent_payment_id = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,3 +276,11 @@ class SqueakAdminServerHandler(object):
|
|||
def handle_get_buy_offer(self, offer_id):
|
||||
logger.info("Handle get buy offer for hash: {}".format(offer_id))
|
||||
return self.squeak_node.get_buy_offer_with_peer(offer_id)
|
||||
|
||||
def handle_sync_squeaks(self):
|
||||
logger.info("Handle get sync squeaks")
|
||||
self.squeak_node.sync_squeaks()
|
||||
|
||||
def handle_pay_offer(self, offer_id):
|
||||
logger.info("Handle pay offer for offer id: {}".format(offer_id))
|
||||
return self.squeak_node.pay_offer(offer_id)
|
||||
|
|
|
|||
|
|
@ -293,6 +293,17 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer):
|
|||
offer=offer_msg,
|
||||
)
|
||||
|
||||
def SyncSqueaks(self, request, context):
|
||||
self.handler.handle_sync_squeaks()
|
||||
return squeak_admin_pb2.SyncSqueaksReply()
|
||||
|
||||
def PayOffer(self, request, context):
|
||||
offer_id = request.offer_id
|
||||
sent_payment_id = self.handler.handle_pay_offer(offer_id)
|
||||
return squeak_admin_pb2.PayOfferReply(
|
||||
sent_payment_id=sent_payment_id,
|
||||
)
|
||||
|
||||
def _squeak_entry_to_message(self, squeak_entry_with_profile):
|
||||
if squeak_entry_with_profile is None:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -764,6 +764,17 @@ class SqueakDb:
|
|||
# # execute the UPDATE statement
|
||||
# curs.execute(sql, (block_header, squeak_hash_str,))
|
||||
|
||||
def set_squeak_decryption_key(self, squeak_hash, vch_decryption_key):
|
||||
""" Set the decryption key of a squeak. """
|
||||
squeak_hash_str = squeak_hash.hex()
|
||||
stmt = (
|
||||
self.squeaks.update()
|
||||
.where(self.squeaks.c.hash == squeak_hash_str)
|
||||
.values(vch_decryption_key=vch_decryption_key)
|
||||
)
|
||||
with self.get_connection() as connection:
|
||||
connection.execute(stmt)
|
||||
|
||||
def delete_squeak(self, squeak_hash):
|
||||
""" Delete a squeak. """
|
||||
squeak_hash_str = squeak_hash.hex()
|
||||
|
|
@ -975,6 +986,23 @@ class SqueakDb:
|
|||
# rows = curs.fetchall()
|
||||
# return len(rows)
|
||||
|
||||
def insert_sent_payment(self, sent_payment):
|
||||
""" Insert a new sent payment. """
|
||||
ins = self.sent_payments.insert().values(
|
||||
offer_id=sent_payment.offer_id,
|
||||
peer_id=sent_payment.peer_id,
|
||||
squeak_hash=sent_payment.squeak_hash,
|
||||
preimage_hash=sent_payment.preimage_hash,
|
||||
preimage=sent_payment.preimage,
|
||||
amount=sent_payment.amount,
|
||||
node_pubkey=sent_payment.node_pubkey,
|
||||
preimage_is_valid=sent_payment.preimage_is_valid,
|
||||
)
|
||||
with self.get_connection() as connection:
|
||||
res = connection.execute(ins)
|
||||
sent_payment_id = res.inserted_primary_key[0]
|
||||
return sent_payment_id
|
||||
|
||||
def _parse_squeak_entry(self, row):
|
||||
if row is None:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import logging
|
||||
|
||||
from squeak.core.encryption import (
|
||||
CEncryptedDecryptionKey,
|
||||
generate_initialization_vector,
|
||||
)
|
||||
from squeak.core.signing import CSigningKey, CSqueakAddress
|
||||
from squeak.core import CheckSqueak
|
||||
|
||||
from squeakserver.core.squeak_address_validator import SqueakAddressValidator
|
||||
from squeakserver.node.squeak_block_periodic_worker import SqueakBlockPeriodicWorker
|
||||
|
|
@ -19,9 +22,13 @@ from squeakserver.node.squeak_whitelist import SqueakWhitelist
|
|||
from squeakserver.server.buy_offer import BuyOffer
|
||||
from squeakserver.server.squeak_peer import SqueakPeer
|
||||
from squeakserver.server.squeak_profile import SqueakProfile
|
||||
from squeakserver.server.sent_payment import SentPayment
|
||||
from squeakserver.server.util import generate_offer_preimage
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SqueakNode:
|
||||
def __init__(
|
||||
self,
|
||||
|
|
@ -256,3 +263,60 @@ class SqueakNode:
|
|||
|
||||
def get_buy_offer_with_peer(self, offer_id):
|
||||
return self.postgres_db.get_offer_with_peer(offer_id)
|
||||
|
||||
def pay_offer(self, offer_id):
|
||||
# Get the offer from the database
|
||||
offer_with_peer = self.postgres_db.get_offer_with_peer(offer_id)
|
||||
offer = offer_with_peer.offer
|
||||
|
||||
# Pay the invoice
|
||||
payment = self.lightning_client.pay_invoice_sync(offer.payment_request)
|
||||
preimage = payment.payment_preimage
|
||||
|
||||
# TODO: Check if preimage is valid
|
||||
is_valid = True
|
||||
|
||||
# Unlock the squeak
|
||||
squeak_entry = self.postgres_db.get_squeak_entry(bytes.fromhex(offer.squeak_hash))
|
||||
squeak = squeak_entry.squeak
|
||||
|
||||
# Verify with the payment preimage and decryption key ciphertext
|
||||
decryption_key_cipher_bytes = offer.key_cipher
|
||||
iv = offer.iv
|
||||
encrypted_decryption_key = CEncryptedDecryptionKey.from_bytes(
|
||||
decryption_key_cipher_bytes
|
||||
)
|
||||
|
||||
# Decrypt the decryption key
|
||||
decryption_key = encrypted_decryption_key.get_decryption_key(preimage, iv)
|
||||
serialized_decryption_key = decryption_key.get_bytes()
|
||||
|
||||
# Check the decryption key
|
||||
squeak.SetDecryptionKey(serialized_decryption_key)
|
||||
CheckSqueak(squeak)
|
||||
logger.info("squeak.GetDecryptedContentStr():")
|
||||
logger.info(squeak.GetDecryptedContentStr())
|
||||
|
||||
# Set the decryption key in the database
|
||||
self.squeak_store.unlock_squeak(
|
||||
bytes.fromhex(offer.squeak_hash),
|
||||
serialized_decryption_key,
|
||||
)
|
||||
|
||||
# Save the preimage of the sent payment
|
||||
sent_payment = SentPayment(
|
||||
sent_payment_id=None,
|
||||
offer_id=offer_id,
|
||||
peer_id=offer.peer_id,
|
||||
squeak_hash=offer.squeak_hash,
|
||||
preimage_hash=offer.payment_hash,
|
||||
preimage=preimage,
|
||||
amount=offer.price_msat,
|
||||
node_pubkey=offer.destination,
|
||||
preimage_is_valid=is_valid,
|
||||
)
|
||||
sent_payment_id = self.postgres_db.insert_sent_payment(sent_payment)
|
||||
return sent_payment_id
|
||||
|
||||
def sync_squeaks(self):
|
||||
self.squeak_peer_sync_worker.sync_peers()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class SqueakPeerSyncWorker:
|
|||
def sync_peers(self):
|
||||
logger.info("Syncing peers...")
|
||||
peers = self._get_peers()
|
||||
logger.info("Syncing peers: {}".format(peers))
|
||||
self.squeak_sync_controller.sync_peers(peers)
|
||||
|
||||
def start_running(self):
|
||||
|
|
|
|||
|
|
@ -96,3 +96,9 @@ class SqueakStore:
|
|||
max_block,
|
||||
peer_id,
|
||||
)
|
||||
|
||||
def unlock_squeak(self, squeak_hash, vch_decryption_key):
|
||||
self.postgres_db.set_squeak_decryption_key(
|
||||
squeak_hash,
|
||||
vch_decryption_key,
|
||||
)
|
||||
|
|
|
|||
6
squeakserver/server/sent_payment.py
Normal file
6
squeakserver/server/sent_payment.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from collections import namedtuple
|
||||
|
||||
SentPayment = namedtuple(
|
||||
"SentPayment",
|
||||
"sent_payment_id, offer_id, peer_id, squeak_hash, preimage_hash, preimage, amount, node_pubkey, preimage_is_valid",
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue