Skip to content
Snippets Groups Projects
Commit 5ba6fcbe authored by Robert Martin-Legene's avatar Robert Martin-Legene
Browse files

Commit of package initially distributed via mail.

parents
No related branches found
No related tags found
No related merge requests found
README 0 → 100644
1) Install Ubuntu
2) add-apt-repository -y ppa:ethereum/ethereum
3) apt update
4) apt install ethereum solc jq ncurses-bin
5) run start.sh
6) create your contract (there is already one deployed, so *do*not* confuse the two)
7) insert.sh "I'm doing great today."
8) wait for next block to be sealed/mined: sleep 15
9) verify.sh "Hi there"
10) verify.sh "I'm doing great today."
11) Try the basic explorer.sh
12) consider this crontab: @reboot bfa/network5445/start.sh
== network5445/start.sh
requires: geth
Starts a node on the 5445 BFA test net. Creates a genesis.json if you don't have one already.
One is already included in this package, which will allow you to connect to the existing BFA testnet.
== create.contract
requires: geth, solc, jq
Compiles and deploys a contract to the blockchain. A local "node1" must already be running.
Argument 1 is the contract to compile.
Example: ./create.contract src/contract.TimestampDocument.sol
== insert.sh
requires: geth
Inserts the checksum of a text into the compiled contract.
== verify.sh
requires: geth
Returns the first blocknumber where the SHA256 checksum of a document was seen (0 for no match).
== explorer.sh
requires: curl, jq, tput (ncurses-bin)
Simple script to look at blocks
== src/contract.TimestampDocument.sol
The initial Timestamp service. Could be made better.
"[{\"constant\":true,\"inputs\":[{\"name\":\"document\",\"type\":\"string\"}],\"name\":\"checkDocument\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"document\",\"type\":\"string\"}],\"name\":\"storeDocument\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
0x80acee1f07c3bbe1f6e9bd5f1ef455a4d6d71025
\ No newline at end of file
#!/bin/bash
function prereq
{
err=0
while [ -n "$1" ]
do
if ! which $1 > /dev/null
then
echo "Need $1"
err=1
fi
shift
done
test $err -eq 0 || exit 1
}
function cleanup
{
rmfiles="$rmfiles $@"
trap "rm -rf ${rmfiles}" EXIT
}
function create
{
workdir=`mktemp -p . -d`
cleanup "${workdir}"
json=$( solc --optimize --combined-json abi,bin $filename )
prefix=$( echo "$json" | jq '.contracts|keys[0]' )
abi=$( echo "$json" | jq ".contracts.${prefix}.abi" )
bin=$( echo "$json" | jq ".contracts.${prefix}.bin" )
bin="${bin//\"}"
echo $abi > ${workdir}/abi
#echo $bin > ${workdir}/bin
cleanup g1.js
cat > g1.js <<EOT
var mycontract = eth.contract(JSON.parse($abi))
var transaction = mycontract.new( { from: eth.accounts[0], data: "0x${bin}", gas: 1000000 } )
var rcpt
while ( !rcpt )
{
admin.sleepBlocks( 1 );
rcpt = eth.getTransactionReceipt( transaction.transactionHash );
}
var address = rcpt.contractAddress;
var pubcontract = mycontract.at(address);
console.log( pubcontract.address );
EOT
echo '*** Creating contract. Will take 16-30 seconds'
cleanup out1
geth --datadir network5445/node1 --password /dev/null --unlock $account --exec 'loadScript("g1.js")' attach ipc:network5445/node1/geth.ipc > out1
if [ ` wc -l < out1 ` = 2 -a `tail -1 < out1` = "true" ]
then
addr=` head -1 < out1 `
mkdir -p contracts
mv ${workdir} contracts/${addr}
echo Your new contract can be found in contracts/${addr}
ln -sf ${addr} contracts/${contractname}
else
cat g1.js
echo
echo ' ***'
echo
cat out1
fi
}
trap "echo Argh;exit 1" ERR
test -n "$1" || ( echo "Specify a filename of a contract you wish to compile."; false )
filename="$1"
test -r "$filename"
contractname=${filename%%.sol}
contractname=${contractname##*/}
contractname=${contractname##contract.}
contractname=${contractname%.*}
account=` ls -1dl network5445/node1/keystore/* | head -1 | sed 's/.*--//' `
test -n "$account"
prereq jq solc geth
create
#!/bin/bash
function cleanup
{
rmfiles="$rmfiles $@"
trap "rm -rf ${rmfiles}" EXIT
}
in=$1
test -n "$in" || in="Hello World!"
trap "echo Argh;exit 1" ERR
account=` ls -1dl network5445/node1/keystore/* | head -1 | sed 's/.*--//' `
test -n "$account"
contract=$( readlink contracts/TimestampDocument )
abi=$( cat contracts/${contract}/abi )
cleanup g1.js
cat > g1.js <<EOT
var mycontract = eth.contract(JSON.parse($abi))
var thecontract = mycontract.at("$contract");
console.log ( thecontract.storeDocument.sendTransaction( "${in}", {from: eth.accounts[0], gas: 1000000} ) )
EOT
cleanup out1
geth --datadir network5445/node1 --password /dev/null --unlock $account --exec 'loadScript("g1.js")' attach ipc:network5445/node1/geth.ipc > out1
if [ ` wc -l < out1 ` = 2 -a `tail -1 < out1` = "true" ]
then
conf=` head -1 < out1 `
echo "Sent document in transaction ${conf}."
else
cat g1.js
echo
echo ' ***'
echo
cat out1
fi
#!/bin/bash
# 20180619 Robert Martin-Legene <robert@nic.ar>
trap "echo Argh;exit 1" ERR
rpcport=8545
cd $( dirname $0 )
test -r "node1/rpcport" &&
rpcport=$( cat node1/rpcport )
test -n "$rpcport"
width=$( tput cols )
height=$( tput lines )
block=${1:-0}
function showblock
{
hexblock=$( printf '%x' $1 )
printf '\e[H\e[JBlock %d (0x%x)\n' $block $block
curl -H 'Content-type: application/json' -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x'${hexblock}'", true],"id":1}' http://127.0.0.1:$rpcport 2>/dev/null |
jq -C . |
fold --width=$width |
head -$(( $height - 2 ))
printf '\e[m'
}
showblock $block
while read -r -s -n 1 -p "j=up k=down q=quit "
do
if [ "${REPLY,,}" = "q" ]
then
echo
exit 0
elif [ "${REPLY,,}" = "k" -a $block -gt 0 ]
then
let block--
elif [ "${REPLY,,}" = "j" ]
then
let block++ || true
fi
showblock $block
done
{
"config": {
"chainId": 5445,
"homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 4,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"clique": { "period": 15, "epoch": 30000 }
},
"nonce": "0x0000000000000000",
"timestamp": "0x5b293735",
"extraData": "0x426c6f636b636861696e204665646572616c20417267656e74696e61204e49432fd693d1204907ae7d97b5d7d2e93ef877ef2c7d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0xffeeddcc", "difficulty": "0x1", "number": "0x0", "gasUsed": "0x0",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"alloc": { "2fd693d1204907ae7d97b5d7d2e93ef877ef2c7d": { "balance": "0x200000000000000000000000000000000000000000000000000000000000000" } }
}
#!/bin/bash
trap "exit 1" ERR
if [ -n "$1" ]
then
dir="$1"
else
dir=node1
fi
SECONDS=$( date +%s )
cd `dirname $0`
function repeat
{
printf -- "$2%0.s" $( seq 1 $1 )
}
function gen_genesis
{
nodes=$( ls -1d node*/keystore/* | sed 's/.*--//' )
test -n "$nodes" &&
echo "Found local nodes:" $nodes
echo "** If you want extra nodes added, add them to nodes.remote.txt and run $0 again."
test -r "nodes.remote.txt" &&
nodes="${nodes} $( cat nodes.remote.txt )"
allocs=
sealers=
for node in ${nodes}
do
allocs="${allocs}"$(
printf ', "%s": { "balance": "%s" }' \
$node \
0x200000000000000000000000000000000000000000000000000000000000000
)
sealers="${sealers}${node}"
done
allocs="${allocs:2}"
cat << EOCONF > genesis.json
{
"config": {
"chainId": ${network},
"homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 4,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"clique": { "period": 15, "epoch": 30000 }
},
"nonce": "0x0000000000000000",
"timestamp": "$( printf '0x%08x' $SECONDS )",
"extraData": "0x426c6f636b636861696e204665646572616c20417267656e74696e61204e4943${sealers}$( repeat 130 0 )",
"gasLimit": "0xffeeddcc", "difficulty": "0x1", "number": "0x0", "gasUsed": "0x0",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"alloc": { $allocs }
}
EOCONF
}
# Get network id
for part in `pwd | sed 's,/, ,g'`
do
if [ "${part:0:7}" = "network" ]
then
network=${part:7}
fi
done
# Create an account if none was found.
test ` ls -1 ${dir}/keystore 2>/dev/null | wc -l ` -ge 1 ||
geth --datadir ${dir} --password /dev/null account new
# Create a genesis.json if one does not already exist
test -r genesis.json ||
gen_genesis
# Initialise if needed
test -d ${dir}/geth/chaindata ||
geth --datadir ${dir} init genesis.json
# Fix on a random port number.
test -r ${dir}/port ||
echo $(( $RANDOM / 2 + 12345 )) > ${dir}/port
test -r ${dir}/rpcport ||
echo $(( $RANDOM / 2 + 12345 )) > ${dir}/rpcport
port=$( cat ${dir}/port )
rpcport=$( cat ${dir}/rpcport )
account=$( ls -1ld ${dir}/keystore/* | head -1 | sed 's/.*--//' )
verbosity=0
if [ -t 1 ]
then
verbosity=3
set -x
fi
# Start the miner.
exec flock --nonblock --exclusive ${dir}/rpcport \
geth \
--datadir ${dir} \
--unlock "$account" \
--password /dev/null \
--mine \
--networkid $network \
--rpc \
--rpcport $rpcport \
--port $port \
--syncmode full \
--nousb \
--bootnodes 'enode://6c81b38551fec2f1142b58ed65137cc1b7dfdc7b35bc556ef26604c41e30fcdeb12212b3c19913584f71dc7bf87d76cd67fa523e96996c0f148390fb76fdc5f7@[200.68.65.135]:5445' \
--verbosity ${verbosity}
// 20180612 Robert Martin-Legene <robert@nic.ar>
// It can be difficult to feed large binary "documents" into this
// routine, so it should be changed to accept just the checksum,
// so we'll call this v0.1
pragma solidity ^0.4.24;
contract TimestampDocument {
// This mapping is almost an "associative array"
mapping (bytes32 => uint) private hashes;
// Public functions
//
// Calculate and store the hash for a document
//
function storeDocument( string document ) public {
bytes32 hash = sha256(abi.encodePacked(document));
storeHash( hash );
}
//
// Returns the block number a hash was first seen in.
// zero (0) means not found.
//
function checkDocument( string document ) public view returns (uint) {
return getBlock( sha256(abi.encodePacked(document)) );
}
// Private functions
//
// Stores the hash of the document in the mapping
// if we have not seen the hash before.
//
function storeHash( bytes32 hash ) private {
if ( hashes[hash] == 0 ) {
hashes[hash] = block.number;
}
}
//
// Returns the block number in which the hash was first seen,
// or zero (0) if never seen.
//
function getBlock( bytes32 hash ) private view returns (uint) {
return hashes[hash];
}
}
#!/bin/bash
function cleanup
{
rmfiles="$rmfiles $@"
trap "rm -rf ${rmfiles}" EXIT
}
in=$1
test -n "$in" || in="Hello World!"
trap "echo Argh;exit 1" ERR
account=` ls -1dl network5445/node1/keystore/* | head -1 | sed 's/.*--//' `
test -n "$account"
contract=$( readlink contracts/TimestampDocument )
abi=$( cat contracts/${contract}/abi )
cleanup g1.js
cat > g1.js <<EOT
var mycontract = eth.contract(JSON.parse($abi))
var thecontract = mycontract.at("$contract");
console.log ( thecontract.checkDocument.call( "${in}" ) )
EOT
cleanup out1
geth --datadir network5445/node1 --password /dev/null --unlock $account --exec 'loadScript("g1.js")' attach ipc:network5445/node1/geth.ipc > out1
if [ ` wc -l < out1 ` = 2 -a `tail -1 < out1` = "true" ]
then
block=` head -1 < out1 `
if [ "$block" = "0" ]
then
echo "The checksum of this document has not been stored in the smart contract (yet?)."
else
echo "Document first seen in block ${block}"
fi
else
cat g1.js
echo
echo ' ***'
echo
cat out1
fi
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment