early concept v1

This commit is contained in:
2024-04-23 13:56:26 +03:00
commit acd2108381
14 changed files with 432 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.swp
data/

86
accept_deal.sh Executable file
View File

@@ -0,0 +1,86 @@
#!/bin/bash
set -xue
. ./config.sh
PREV_ID=$(cat "$DEALS_PREV_MESSAGE_ID_FOR_ACCEPT" || echo "")
NEW_PREV_ID_FILE="${DEALS_PREV_MESSAGE_ID_FOR_ACCEPT}.new"
TEXT_FILE="${DEALS_BASE}/accept_message.txt"
SENDER_FILE="${DEALS_BASE}/sender.txt"
python get_bm_message.py \
--to-address "$DEALS_BM_TO_ACCEPT_DEALS" \
--from-address "$SENDER_FILE" \
--prev-id "$PREV_ID" \
--output-id "$NEW_PREV_ID_FILE" \
--output-text "$TEXT_FILE"
if [ ! -f "$NEW_PREV_ID_FILE" ]; then
echo "No new messages"
exit 0
fi
# BM message id is used as deal ID.
DEAL_ID=$(cat "$NEW_PREV_ID_FILE")
mv "$NEW_PREV_ID_FILE" "$DEALS_PREV_MESSAGE_ID_FOR_ACCEPT"
mkdir -p "$DEALS_INPUTS_DB_ROOT"
INPUT_FILE="${DEALS_INPUTS_DB_ROOT}/${DEAL_ID}"
mv "$TEXT_FILE" "$INPUT_FILE"
PAYER_BTC=$(grep "payer_btc: " "$INPUT_FILE" | sed "s/^payer_btc: //" | sed 's/"//g' | sed "s/'//g")
PAYEE_BTC=$(grep "payee_btc: " "$INPUT_FILE" | sed "s/^payee_btc: //" | sed 's/"//g' | sed "s/'//g")
AMOUNT=$(grep "amount: " "$INPUT_FILE" | sed "s/^amount: //" | sed 's/"//g' | sed "s/'//g" | sed "s/ BTC$//" )
MEMO="deposit for deal ${DEAL_ID}"
mkdir -p "$DEALS_PAYER_BTC"
mkdir -p "$DEALS_PAYEE_BTC"
echo "$PAYER_BTC" > "${DEALS_PAYER_BTC}/${DEAL_ID}"
echo "$PAYEE_BTC" > "${DEALS_PAYEE_BTC}/${DEAL_ID}"
NOW=$(date +"%s")
NOW_STR=$(date -u "-d@${NOW}")
EXPIRATION=$(($NOW + $DEALS_DEPOSIT_TIMEOUT))
EXPIRATION_STR=$(date -u "-d@${EXPIRATION}")
mkdir -p "$DEALS_REQUEST_DB_ROOT"
REQUEST_FILE="${DEALS_REQUEST_DB_ROOT}/${DEAL_ID}"
if [ -f "$REQUEST_FILE" ] ; then
echo "File ${REQUEST_FILE} already exists"
exit 1
fi
$ELECTRUM addrequest "$AMOUNT" -m "$MEMO" --expiration "$DEALS_DEPOSIT_TIMEOUT" > "$REQUEST_FILE"
DEPOSIT_ADDRESS=$(cat "$REQUEST_FILE" | grep '"address": ' | sed 's/"address": //' | sed 's/[ ",]//g')
APPROVED_DEAL="${DEALS_BASE}/approved_deal.txt"
cp "$INPUT_FILE" "$APPROVED_DEAL"
echo '' >> "$APPROVED_DEAL"
echo "deal: ${DEAL_ID}" >> "$APPROVED_DEAL"
echo "to_bitcoin: ${DEPOSIT_ADDRESS}" >> "$APPROVED_DEAL"
echo "date: '${NOW_STR}'" >> "$APPROVED_DEAL"
echo "pay_until: '${EXPIRATION_STR}'" >> "$APPROVED_DEAL"
mkdir -p "$DEALS_SIGNED_APPROVED_DEALS_DB_ROOT"
SIGNED_FILE="${DEALS_SIGNED_APPROVED_DEALS_DB_ROOT}/${DEAL_ID}"
if [ -f "$SIGNED_FILE" ] ; then
echo "File ${SIGNED_FILE} already exists"
exit 1
fi
mkdir -p "$DEALS_DEAL_SENDERS"
cp "$SENDER_FILE" "${DEALS_DEAL_SENDERS}/${DEAL_ID}"
gpg -o "$SIGNED_FILE" --sign-with="$DEALS_PGP_TO_ACK_DEAL" --clear-sign "$APPROVED_DEAL"
python send_bm_message.py \
--from-address "$DEALS_BM_TO_ACCEPT_DEALS" \
--to-address "$(cat "$SENDER_FILE" )" \
--subject "" \
--message-file "$SIGNED_FILE"

6
accept_deal_example.yaml Normal file
View File

@@ -0,0 +1,6 @@
date: "2018-03-20 17:09:00"
payer: mgP3agvYaFktZN1mGpERVZU2CMLysD3EWN
payer_btc: mgP3agvYaFktZN1mGpERVZU2CMLysD3EWN
payee: jane
payee_btc: mzLaUbq8pXtZHzvQrpMdsE269Ny2whcyjx
amount: "0.01 BTC"

36
config.sh Normal file
View File

@@ -0,0 +1,36 @@
#!/bin/bash
DEALS_BASE="data"
mkdir -p "$DEALS_BASE"
DEALS_BM_FOR_REGISTRATIONS="BM-2cTfyagTwT8d7UeqQRnAcMkczyUmn9WHmS"
DEALS_PREV_MESSAGE_ID_FOR_REGISTRATIONS="${DEALS_BASE}/registrations_last_message_id.txt"
DEALS_REG_DB_ROOT="${DEALS_BASE}/users/"
DEALS_BM_TO_ACCEPT_DEALS="BM-2cVtzJWsb2F7Me1Xhyf2UQXikacJW4uvsX"
DEALS_PREV_MESSAGE_ID_FOR_ACCEPT="${DEALS_BASE}/accept_last_message_id.txt"
DEALS_INPUTS_DB_ROOT="${DEALS_BASE}/deal_inputs/"
DEALS_REQUEST_DB_ROOT="${DEALS_BASE}/deal_requests/"
DEALS_DEAL_SENDERS="${DEALS_BASE}/deal_senders/"
DEALS_SIGNED_APPROVED_DEALS_DB_ROOT="${DEALS_BASE}/signed_approved_deals/"
DEALS_BM_TO_NOTIFY_BALANCE_UPDATES="BM-2cVtzJWsb2F7Me1Xhyf2UQXikacJW4uvsX"
DEALS_LAST_BALANCE="${DEALS_BASE}/request_last_balance/"
DEALS_FILLED="${DEALS_BASE}/request_filled/"
DEALS_PAYER_BTC="${DEALS_BASE}/payer_btc/"
DEALS_PAYEE_BTC="${DEALS_BASE}/payee_btc/"
DEALS_PGP_TO_ACK_DEAL="F451DDCB84456DAABDF72C6EB513FB92284223A4"
DEALS_BM_TO_SEND_DEAL_ACK="BM-2cVtzJWsb2F7Me1Xhyf2UQXikacJW4uvsX"
DEALS_JUDGE_PGP="228EA88DCD8221723E6CC671A298E92820BE01C9"
DEALS_JUDGE_BM_DESTINATION="BM-2cWK3BTH4JBbUjGpb4zMsYwHEcxHtyhqxw"
DEALS_JUDGE_BM_SOURCE="BM-2cUDy5DDuunJgYgjdC1E5AvMY3dVYcSrQZ"
DEALS_PREV_MESSAGE_ID_FOR_JUDGE="${DEALS_BASE}/judge_last_message_id.txt"
DEALS_JUDGE_MESSAGES="${DEALS_BASE}/judge_messages/"
DEALS_FINISHED="${DEALS_BASE}/request_finished/"
# Time to fill deposit address, in seconds.
DEALS_DEPOSIT_TIMEOUT=86400
ELECTRUM="electrum --testnet"

38
get_bm_message.py Normal file
View File

@@ -0,0 +1,38 @@
import argparse
import base64
import json
import xmlrpclib
def get_next_message(api, to_address, prev_id):
messages = json.loads(api.getAllInboxMessages())['inboxMessages']
messages = [m for m in messages if m['toAddress'] == to_address]
if len(messages) == 0:
return None
if not prev_id:
return messages[0]
for (prev, next) in zip(messages, messages[1:]):
if prev['msgid'] == prev_id:
return next
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--prev-id')
parser.add_argument('--api', default="http://username:password@127.0.0.1:8442/")
parser.add_argument('--to-address')
parser.add_argument('--from-address')
parser.add_argument('--output-id')
parser.add_argument('--output-text')
args = parser.parse_args()
api = xmlrpclib.ServerProxy(args.api)
next_message = get_next_message(api, args.to_address, args.prev_id)
if not next_message:
return
with open(args.output_text, 'w') as f:
f.write(base64.b64decode(next_message['message']))
with open(args.output_id, 'w') as f:
f.write(next_message['msgid'])
with open(args.from_address, 'w') as f:
f.write(next_message['fromAddress'])
if __name__ == '__main__':
main()

69
judge.sh Executable file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
set -xue
. ./config.sh
PREV_ID=$(cat "$DEALS_PREV_MESSAGE_ID_FOR_JUDGE" || echo "")
NEW_PREV_ID_FILE="${DEALS_PREV_MESSAGE_ID_FOR_JUDGE}.new"
TEXT_FILE="${DEALS_BASE}/judge_message.txt.asc"
SENDER_FILE="${DEALS_BASE}/judge_sender.txt"
python get_bm_message.py \
--to-address "$DEALS_JUDGE_BM_DESTINATION" \
--from-address "$SENDER_FILE" \
--prev-id "$PREV_ID" \
--output-id "$NEW_PREV_ID_FILE" \
--output-text "$TEXT_FILE"
if [ ! -f "$NEW_PREV_ID_FILE" ]; then
echo "No new messages"
exit 0
fi
mv "$NEW_PREV_ID_FILE" "$DEALS_PREV_MESSAGE_ID_FOR_JUDGE"
SENDER="$(cat "$SENDER_FILE" )"
if [ "$SENDER" != "$DEALS_JUDGE_BM_SOURCE" ]; then
echo "Sender is not our judge"
exit 1
fi
DEAL=$(grep 'deal:' "$TEXT_FILE" | sed 's/deal: //')
mkdir -p "$DEALS_JUDGE_MESSAGES"
TEXT_FILE_CONTENT="${DEALS_JUDGE_MESSAGES}/${DEAL}"
gpg -o "$TEXT_FILE_CONTENT" "$TEXT_FILE" 2> "${DEALS_BASE}/gpg_stderr.txt"
if ! grep "$DEALS_JUDGE_PGP" "${DEALS_BASE}/gpg_stderr.txt" ; then
echo "GPG check failed"
exit 1
fi
mkdir -p "$DEALS_FINISHED"
FINISHED_FILE="${DEALS_FINISHED}/${DEAL}"
if [ -f "$FINISHED_FILE" ] ; then
echo "Deal ${DEAL} has been jusged already"
exit 0
fi
touch "$FINISHED_FILE"
SEND_BTC=$(grep 'send_btc:' "$TEXT_FILE_CONTENT" | sed 's/send_btc: //')
BTC_ADDRESS_FILE="${DEALS_BASE}/${SEND_BTC}_btc/${DEAL}"
if [ ! -f "$BTC_ADDRESS_FILE" ] ; then
echo "File ${BTC_ADDRESS_FILE} does not exist"
exit 1
fi
BTC_ADDRESS="$(cat "$BTC_ADDRESS_FILE")"
INPUT_FILE="${DEALS_INPUTS_DB_ROOT}/${DEAL}"
AMOUNT=$(grep "amount: " "$INPUT_FILE" | sed "s/^amount: //" | sed 's/"//g' | sed "s/'//g" | sed "s/ BTC$//" )
$ELECTRUM payto "$BTC_ADDRESS" "$AMOUNT" | $ELECTRUM broadcast -

16
judgement_example.txt.asc Normal file
View File

@@ -0,0 +1,16 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
deal: 9762456efae9abc483d8a25273e6d22ea1938c3a46f1e9893c14806dc4bf1d55
send_btc: payee
-----BEGIN PGP SIGNATURE-----
iQEzBAEBCAAdFiEEIo6ojc2CIXI+bMZxopjpKCC+AckFAlrekAgACgkQopjpKCC+
Acl1Twf/dvkx81m13zfgPjaLzgdZ43erIiCtT2YTTcdszXTJc/fO+MH2sluNQwvs
oNeQhDnvRaZeG8MjepU1PXuOIdSEpdZGsh39tKSo25zBsQCIrlHcEtBHIDkP2q5I
4KIRaxdq0WERu7URRr1tUrvH13J15GaaabC9pbDa+aoXpXdro1vsU7C8IrndA1OS
OTdgJF/avlxLWqWPCHZdajpKVFEtwjCk+T+C89GiBbJh5O8823amCy8P9U6N5OJx
bkftghe6i15tCSJCHGNN53Ld0HyR2T1vSalyH2sk7ItWbvoclvJCm40hdPJfshN/
rICKse8G+aCmQLiwtZNhjFPAkgziYg==
=oyDj
-----END PGP SIGNATURE-----

44
read_registrations.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/bash
set -xue
. ./config.sh
PREV_ID=$(cat "$DEALS_PREV_MESSAGE_ID_FOR_REGISTRATIONS" || echo "")
NEW_PREV_ID_FILE="${DEALS_PREV_MESSAGE_ID_FOR_REGISTRATIONS}.new"
TEXT_FILE="${DEALS_BASE}/message.txt"
python get_bm_message.py \
--to-address "$DEALS_BM_FOR_REGISTRATIONS" \
--prev-id "$PREV_ID" \
--output-id "$NEW_PREV_ID_FILE" \
--output-text "$TEXT_FILE" \
--from-address /dev/null
if [ ! -f "$NEW_PREV_ID_FILE" ]; then
echo "No new messages"
exit 0
fi
NAME=$(grep "name: " "$TEXT_FILE" | sed "s/^name: //" || echo "")
if [ "$NAME" == "" ]; then
echo "Failed to parse registration message"
else
if ! ( echo "$NAME" | egrep --quiet '^[a-zA-Z0-9_]{3,10}$' ) ; then
echo "Name ${NAME} is not acceptable"
else
mkdir -p "$DEALS_REG_DB_ROOT"
DB_FILE="${DEALS_REG_DB_ROOT}/${NAME}"
if [ -f "$DB_FILE" ]; then
echo "User ${NAME} already exists"
else
echo "Registering user ${NAME}"
mv "$TEXT_FILE" "$DB_FILE"
fi
fi
fi
mv "$NEW_PREV_ID_FILE" "$DEALS_PREV_MESSAGE_ID_FOR_REGISTRATIONS"

View File

@@ -0,0 +1,6 @@
name: jane
registering_user: parent
bitcoin_address: 16sXwXeqJpAzh7T9mkTm352D6nXbJqQS4N
email: foo@bar.com
onion: blockchainbdgpzk.onion
note: arbitrary text here

20
send_bm_message.py Normal file
View File

@@ -0,0 +1,20 @@
import argparse
import base64
import json
import xmlrpclib
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--api', default="http://username:password@127.0.0.1:8442/")
parser.add_argument('--from-address')
parser.add_argument('--to-address')
parser.add_argument('--subject')
parser.add_argument('--message-file')
args = parser.parse_args()
api = xmlrpclib.ServerProxy(args.api)
with open(args.message_file) as f:
text = f.read()
api.sendMessage(args.to_address, args.from_address, base64.standard_b64encode(args.subject), base64.standard_b64encode(text), 2)
if __name__ == '__main__':
main()

33
setup.txt Normal file
View File

@@ -0,0 +1,33 @@
Consigure the system by editing config.sh
You can change BM addresses, deal filling timeout (DEALS_DEPOSIT_TIMEOUT),
electrum command to use (ELECTRUM, by default it uses testnet), PGP keys
to use (DEALS_PGP_TO_ACK_DEAL to sign deals, DEALS_JUDGE_PGP to check
arbitration commands). You can change location of all files created bu the
system: DEALS_BASE.
Add the following to ~/.config/PyBitmessage/keys.dat :
apienabled = true
apiport = 8442
apiinterface = 127.0.0.1
apiusername = username
apipassword = password
Run BitMessage.
Setup electrum:
. config.sh
$ELECTRUM setconfig rpcport 7777
$ELECTRUM setconfig rpcuser "username"
$ELECTRUM setconfig rpcpassword "password"
$ELECTRUM create
To start and stop Electrum use start_electrum.sh and stop_electrum.sh
Then you run the following scripts in loop:
read_registrations.sh (it reads new registration messages from BM)
accept_deal.sh (reads new deal creation messages from BM)
update_deals.sh (checks state of deal filling with money)
judge.sh (receives arbitration messages)

8
start_electrum.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
set -xue
. ./config.sh
$ELECTRUM daemon start
$ELECTRUM daemon load_wallet

7
stop_electrum.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -xue
. ./config.sh
$ELECTRUM daemon stop

61
update_deals.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
set -xue
. ./config.sh
mkdir -p "$DEALS_LAST_BALANCE"
MESSAGE_TXT="${DEALS_BASE}/message.txt"
PAID_REQUESTS="${DEALS_BASE}/paid_requests.json"
PENDING_REQUESTS="${DEALS_BASE}/pending_requests.json"
$ELECTRUM listrequests --pending > "$PENDING_REQUESTS"
for deal in $(grep 'deposit for deal' "$PENDING_REQUESTS" | egrep -o '[0-9a-f]{64}'); do
DEPOSIT_ADDRESS=$(grep "$deal" -B 5 "$PENDING_REQUESTS" | grep '"address":' | sed 's/"address": //' | sed 's/[ ",]//g')
BALANCE=$($ELECTRUM getaddressbalance "$DEPOSIT_ADDRESS" | grep '"confirmed"' | sed 's/"confirmed": "//' | sed 's/[" ,]//g')
BALANCE_FILE="${DEALS_LAST_BALANCE}/${deal}"
PREV_BALANCE=$(cat "$BALANCE_FILE" || echo '')
if [ "$BALANCE" = "$PREV_BALANCE" ]; then
echo "No changes for balance of deal ${deal}, address ${DEPOSIT_ADDRESS}"
continue
fi
if [ "$BALANCE" = "0" ]; then
echo "Balance is 0 for deal ${deal}, address ${DEPOSIT_ADDRESS}"
continue
fi
echo "$BALANCE" > "$BALANCE_FILE"
SENDER_FILE="${DEALS_DEAL_SENDERS}/${deal}"
echo "Balance of deal ${deal} updated: ${BALANCE}" > "$MESSAGE_TXT"
python send_bm_message.py \
--from-address "$DEALS_BM_TO_NOTIFY_BALANCE_UPDATES" \
--to-address "$(cat "$SENDER_FILE" )" \
--subject "" \
--message-file "$MESSAGE_TXT"
done
mkdir -p "$DEALS_FILLED"
$ELECTRUM listrequests --paid > "$PAID_REQUESTS"
for deal in $(grep 'deposit for deal' "$PAID_REQUESTS" | egrep -o '[0-9a-f]{64}'); do
FILLED_FILE="${DEALS_FILLED}/${deal}"
if [ -f "$FILLED_FILE" ] ; then
continue
fi
DEPOSIT_ADDRESS=$(grep "$deal" -B 6 "$PAID_REQUESTS" | grep '"address":' | sed 's/"address": //' | sed 's/[ ",]//g')
BALANCE=$($ELECTRUM getaddressbalance "$DEPOSIT_ADDRESS" | grep '"unconfirmed"' | sed 's/"unconfirmed": "//' | sed 's/[" ,]//g')
if [ "$BALANCE" != "0" ]; then
echo "There is unconfirmed money on deal ${deal}, address ${DEPOSIT_ADDRESS}"
continue
fi
touch "$FILLED_FILE"
SENDER_FILE="${DEALS_DEAL_SENDERS}/${deal}"
echo "Deal ${deal} is filled" > "$MESSAGE_TXT"
python send_bm_message.py \
--from-address "$DEALS_BM_TO_NOTIFY_BALANCE_UPDATES" \
--to-address "$(cat "$SENDER_FILE" )" \
--subject "" \
--message-file "$MESSAGE_TXT"
done