mirror of
https://github.com/number571/blockchain.git
synced 2026-09-12 19:50:00 +05:00
fix
This commit is contained in:
parent
07df6d212f
commit
e80b91c176
12
.gitignore
vendored
12
.gitignore
vendored
@ -17,9 +17,9 @@ contracts/Contract.go
|
||||
build/WorldSkills.abi
|
||||
build/WorldSkills.bin
|
||||
abigen
|
||||
!./cmd/node
|
||||
!./cmd/client
|
||||
!./cmd/client_eth
|
||||
!./cmd/gclient
|
||||
!./cmd/gclient_eth
|
||||
!./cmd/deploy
|
||||
!cmd/node
|
||||
!cmd/client
|
||||
!cmd/client_eth
|
||||
!cmd/gclient
|
||||
!cmd/gclient_eth
|
||||
!cmd/deploy
|
||||
|
||||
240
cmd/client/client.go
Normal file
240
cmd/client/client.go
Normal file
@ -0,0 +1,240 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
nt "blockchain-from-scratch/network"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 {
|
||||
panic("failed: len(os.Args) < 2")
|
||||
}
|
||||
var (
|
||||
addrStr = ""
|
||||
userNewStr = ""
|
||||
userLoadStr = ""
|
||||
)
|
||||
var (
|
||||
addrExist = false
|
||||
userNewExist = false
|
||||
userLoadExist = false
|
||||
)
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
arg := os.Args[i]
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "-loadaddr:"):
|
||||
addrStr = strings.Replace(arg, "-loadaddr:", "", 1)
|
||||
addrExist = true
|
||||
case strings.HasPrefix(arg, "-newuser:"):
|
||||
userNewStr = strings.Replace(arg, "-newuser:", "", 1)
|
||||
userNewExist = true
|
||||
case strings.HasPrefix(arg, "-loaduser:"):
|
||||
userLoadStr = strings.Replace(arg, "-loaduser:", "", 1)
|
||||
userLoadExist = true
|
||||
}
|
||||
}
|
||||
|
||||
if !(userNewExist || userLoadExist) || !addrExist {
|
||||
panic("failed: !(userNewExist || userLoadExist) || !addrExist")
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(readFile(addrStr)), &Addresses)
|
||||
if err != nil {
|
||||
panic("failed: load addresses")
|
||||
}
|
||||
if len(Addresses) == 0 {
|
||||
panic("failed: len(Addresses) == 0")
|
||||
}
|
||||
|
||||
if userNewExist {
|
||||
User = userNew(userNewStr)
|
||||
}
|
||||
if userLoadExist {
|
||||
User = userLoad(userLoadStr)
|
||||
}
|
||||
if User == nil {
|
||||
panic("failed: load user")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
handleClient()
|
||||
}
|
||||
|
||||
func handleClient() {
|
||||
var (
|
||||
message string
|
||||
splited []string
|
||||
)
|
||||
for {
|
||||
message = inputString("> ")
|
||||
splited = strings.Split(message, " ")
|
||||
switch splited[0] {
|
||||
case "/exit":
|
||||
os.Exit(0)
|
||||
case "/user":
|
||||
if len(splited) < 2 {
|
||||
fmt.Println("failed: len(user) < 2\n")
|
||||
continue
|
||||
}
|
||||
switch splited[1] {
|
||||
case "address":
|
||||
userAddress()
|
||||
case "purse":
|
||||
userPurse()
|
||||
case "balance":
|
||||
userBalance()
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
case "/chain":
|
||||
if len(splited) < 2 {
|
||||
fmt.Println("failed: len(chain) < 2\n")
|
||||
continue
|
||||
}
|
||||
switch splited[1] {
|
||||
case "print":
|
||||
chainPrint()
|
||||
case "tx":
|
||||
chainTX(splited[1:])
|
||||
case "balance":
|
||||
chainBalance(splited[1:])
|
||||
case "block":
|
||||
chainBlock(splited[1:])
|
||||
case "size":
|
||||
chainSize()
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func chainSize() {
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_CSIZE,
|
||||
})
|
||||
if res == nil || res.Data == "" {
|
||||
fmt.Println("failed: getSize\n")
|
||||
return
|
||||
}
|
||||
fmt.Printf("Size: %s blocks\n\n", res.Data)
|
||||
}
|
||||
|
||||
func chainBlock(splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
num, err := strconv.Atoi(splited[1])
|
||||
if err != nil {
|
||||
fmt.Println("failed: strconv.Atoi(num)\n")
|
||||
return
|
||||
}
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", num-1),
|
||||
})
|
||||
if res == nil || res.Data == "" {
|
||||
fmt.Println("failed: getBlock\n")
|
||||
return
|
||||
}
|
||||
fmt.Printf("[%d] => %s\n", num, res.Data)
|
||||
}
|
||||
|
||||
func chainPrint() {
|
||||
for i := 0; ; i++ {
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", i),
|
||||
})
|
||||
if res == nil || res.Data == "" {
|
||||
break
|
||||
}
|
||||
fmt.Printf("[%d] => %s\n", i+1, res.Data)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func chainTX(splited []string) {
|
||||
if len(splited) != 3 {
|
||||
fmt.Println("failed: len(splited) != 3\n")
|
||||
return
|
||||
}
|
||||
num, err := strconv.Atoi(splited[2])
|
||||
if err != nil {
|
||||
fmt.Println("failed: strconv.Atoi(num)\n")
|
||||
return
|
||||
}
|
||||
for _, addr := range Addresses {
|
||||
res := nt.Send(addr, &nt.Package{
|
||||
Option: GET_LHASH,
|
||||
})
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
tx := bc.NewTransaction(User, bc.Base64Decode(res.Data), splited[1], uint64(num))
|
||||
res = nt.Send(addr, &nt.Package{
|
||||
Option: ADD_TRNSX,
|
||||
Data: bc.SerializeTX(tx),
|
||||
})
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
if res.Data == "ok" {
|
||||
fmt.Printf("ok: (%s)\n", addr)
|
||||
} else {
|
||||
fmt.Printf("fail: (%s)\n", addr)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func chainBalance(splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("fail: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
printBalance(splited[1])
|
||||
}
|
||||
|
||||
func printBalance(useraddr string) {
|
||||
for _, addr := range Addresses {
|
||||
res := nt.Send(addr, &nt.Package{
|
||||
Option: GET_BLNCE,
|
||||
Data: useraddr,
|
||||
})
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Balance (%s): %s coins\n", addr, res.Data)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func userAddress() {
|
||||
fmt.Println("Address:", User.Address(), "\n")
|
||||
}
|
||||
|
||||
func userPurse() {
|
||||
fmt.Println("Purse:", User.Purse(), "\n")
|
||||
}
|
||||
|
||||
func userBalance() {
|
||||
printBalance(User.Address())
|
||||
}
|
||||
|
||||
func inputString(begin string) string {
|
||||
fmt.Print(begin)
|
||||
msg, _ := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
return strings.Replace(msg, "\n", "", 1)
|
||||
}
|
||||
60
cmd/client/values.go
Normal file
60
cmd/client/values.go
Normal file
@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var (
|
||||
Addresses []string
|
||||
User *bc.User
|
||||
)
|
||||
|
||||
const (
|
||||
SEPARATOR = "_SEPARATOR_"
|
||||
)
|
||||
|
||||
const (
|
||||
ADD_BLOCK = iota + 1
|
||||
ADD_TRNSX
|
||||
GET_BLOCK
|
||||
GET_LHASH
|
||||
GET_BLNCE
|
||||
GET_CSIZE
|
||||
)
|
||||
|
||||
func userNew(filename string) *bc.User {
|
||||
user := bc.NewUser()
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
err := writeFile(filename, user.Purse())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func userLoad(filename string) *bc.User {
|
||||
priv := readFile(filename)
|
||||
if priv == "" {
|
||||
return nil
|
||||
}
|
||||
user := bc.LoadUser(priv)
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func writeFile(filename string, data string) error {
|
||||
return ioutil.WriteFile(filename, []byte(data), 0644)
|
||||
}
|
||||
|
||||
func readFile(filename string) string {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
622
cmd/client_eth/client_eth.go
Normal file
622
cmd/client_eth/client_eth.go
Normal file
@ -0,0 +1,622 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"bufio"
|
||||
"context"
|
||||
"strings"
|
||||
"math/big"
|
||||
"encoding/json"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 {
|
||||
panic("failed: len(os.Args) < 2")
|
||||
}
|
||||
var (
|
||||
userLoadStr = ""
|
||||
userLoadExist = false
|
||||
)
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
arg := os.Args[i]
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "-loaduser:"):
|
||||
userLoadStr = strings.Replace(arg, "-loaduser:", "", 1)
|
||||
userLoadExist = true
|
||||
}
|
||||
}
|
||||
if !userLoadExist {
|
||||
panic("failed: !userLoadExist")
|
||||
}
|
||||
if ClientETH == nil {
|
||||
panic("failed: connect to ETH")
|
||||
}
|
||||
if Instance == nil {
|
||||
panic("failed: instance is nil")
|
||||
}
|
||||
User = loadUser(userLoadStr)
|
||||
if User == nil {
|
||||
panic("failed: load user")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var (
|
||||
message string
|
||||
splited []string
|
||||
)
|
||||
for {
|
||||
message = inputString("> ")
|
||||
splited = strings.Split(message, " ")
|
||||
switch splited[0] {
|
||||
case "/exit":
|
||||
os.Exit(0)
|
||||
case "/user":
|
||||
if len(splited) < 2 {
|
||||
fmt.Println("failed: len(user) < 2\n")
|
||||
continue
|
||||
}
|
||||
switch splited[1] {
|
||||
case "address":
|
||||
userAddress()
|
||||
case "purse":
|
||||
userPurse()
|
||||
case "balance":
|
||||
userBalance()
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
case "/chain":
|
||||
if len(splited) < 3 {
|
||||
fmt.Println("failed: len(chain) < 3\n")
|
||||
continue
|
||||
}
|
||||
switch splited[1] {
|
||||
case "get":
|
||||
chainGet(splited[2], splited[2:])
|
||||
case "create":
|
||||
switch splited[2] {
|
||||
case "estate":
|
||||
// chain create estate address info squere usefulSquere
|
||||
chainCreateEstate(splited[2:])
|
||||
case "present":
|
||||
// chain create present id_estate address
|
||||
chainCreatePresent(splited[2:])
|
||||
case "sale":
|
||||
// chain create sale id_estate money
|
||||
chainCreateSale(splited[2:])
|
||||
case "rent":
|
||||
// chain create rent id_estate hours price
|
||||
chainCreateRent(splited[2:])
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
case "cancel":
|
||||
chainCancel(splited[2], splited[2:])
|
||||
case "confirm":
|
||||
switch splited[2] {
|
||||
case "present":
|
||||
// chain confirm present id_present
|
||||
chainConfirmPresent(splited[2:])
|
||||
case "sale":
|
||||
// chain confirm sale id_sale id_customer
|
||||
chainConfirmSale(splited[2:])
|
||||
case "rent":
|
||||
// chain confirm rent id_rent
|
||||
chainConfirmRent(splited[2:])
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
case "try-buy":
|
||||
// chain try-buy id_sale money
|
||||
chainTryBuy(splited[1:])
|
||||
case "cancel-buy":
|
||||
// chain cancel-buy id_sale
|
||||
chainCancelBuy(splited[1:])
|
||||
case "finish-rent":
|
||||
// chain finish-rent id_rent
|
||||
finishRent(splited[1:])
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func chainTryBuy(splited []string) {
|
||||
if len(splited) != 3 {
|
||||
fmt.Println("failed: len(splited) != 3\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
saleNumber = new(big.Int)
|
||||
value = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
saleNumber, ok = saleNumber.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
value, ok = value.SetString(splited[2], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str2) to num\n")
|
||||
return
|
||||
}
|
||||
auth := resetAuth(User)
|
||||
if auth == nil {
|
||||
fmt.Println("failed: auth is nil\n")
|
||||
return
|
||||
}
|
||||
auth.Value = value
|
||||
tx, err := Instance.CheckToBuy(
|
||||
auth,
|
||||
saleNumber,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainCancelBuy(splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
saleNumber = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
saleNumber, ok = saleNumber.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.CancelToBuy(
|
||||
resetAuth(User),
|
||||
saleNumber,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func finishRent(splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
rentNumber = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
rentNumber, ok = rentNumber.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.FinishRent(
|
||||
resetAuth(User),
|
||||
rentNumber,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainCreateEstate(splited []string) {
|
||||
if len(splited) != 5 {
|
||||
fmt.Println("failed: len(splited) != 5\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
squere = new(big.Int)
|
||||
usefulSquere = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
squere, ok = squere.SetString(splited[3], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
usefulSquere, ok = usefulSquere.SetString(splited[4], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str2) to num\n")
|
||||
return
|
||||
}
|
||||
var address common.Address
|
||||
if splited[1] == "my" {
|
||||
address = User.AddressEth
|
||||
} else {
|
||||
address = common.HexToAddress(splited[1])
|
||||
}
|
||||
tx, err := Instance.CreateEstate(
|
||||
resetAuth(User),
|
||||
address,
|
||||
splited[2],
|
||||
squere,
|
||||
usefulSquere,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainCreatePresent(splited []string) {
|
||||
if len(splited) != 3 {
|
||||
fmt.Println("failed: len(splited) != 3\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
estateId = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
estateId, ok = estateId.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.CreatePresent(
|
||||
resetAuth(User),
|
||||
estateId,
|
||||
common.HexToAddress(splited[2]),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainCreateSale(splited []string) {
|
||||
if len(splited) != 3 {
|
||||
fmt.Println("failed: len(splited) != 3\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
estateId = new(big.Int)
|
||||
price = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
estateId, ok = estateId.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
price, ok = price.SetString(splited[2], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str2) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.CreateSale(
|
||||
resetAuth(User),
|
||||
estateId,
|
||||
price,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainCreateRent(splited []string) {
|
||||
if len(splited) != 4 {
|
||||
fmt.Println("failed: len(splited) != 4\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
estateId = new(big.Int)
|
||||
hours = new(big.Int)
|
||||
price = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
estateId, ok = estateId.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
hours, ok = hours.SetString(splited[2], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str2) to num\n")
|
||||
return
|
||||
}
|
||||
price, ok = price.SetString(splited[3], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str3) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.CreateRent(
|
||||
resetAuth(User),
|
||||
estateId,
|
||||
hours,
|
||||
price,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainCancel(category string, splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
tx *types.Transaction
|
||||
err error
|
||||
num = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num, ok = num.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
switch category {
|
||||
case "present":
|
||||
tx, err = Instance.CancelPresent(
|
||||
resetAuth(User),
|
||||
num,
|
||||
)
|
||||
case "sale":
|
||||
tx, err = Instance.CancelSale(
|
||||
resetAuth(User),
|
||||
num,
|
||||
)
|
||||
case "rent":
|
||||
tx, err = Instance.CancelRent(
|
||||
resetAuth(User),
|
||||
num,
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainConfirmPresent(splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
presentNumber = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
presentNumber, ok = presentNumber.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.ConfirmPresent(
|
||||
resetAuth(User),
|
||||
presentNumber,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainConfirmSale(splited []string) {
|
||||
if len(splited) != 3 {
|
||||
fmt.Println("failed: len(splited) != 3\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
saleNumber = new(big.Int)
|
||||
saleTo = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
saleNumber, ok = saleNumber.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
saleTo, ok = saleTo.SetString(splited[2], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str2) to num\n")
|
||||
return
|
||||
}
|
||||
tx, err := Instance.ConfirmSale(
|
||||
resetAuth(User),
|
||||
saleNumber,
|
||||
saleTo,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainConfirmRent(splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
rentNumber = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
rentNumber, ok = rentNumber.SetString(splited[1], 10)
|
||||
if !ok {
|
||||
fmt.Println("failed: conv(str1) to num\n")
|
||||
return
|
||||
}
|
||||
rent := getRents(rentNumber)
|
||||
if rent == nil {
|
||||
fmt.Println("failed: get rent\n")
|
||||
return
|
||||
}
|
||||
auth := resetAuth(User)
|
||||
if auth == nil {
|
||||
fmt.Println("failed: auth is nil\n")
|
||||
return
|
||||
}
|
||||
auth.Value = rent.Money
|
||||
tx, err := Instance.ToRent(
|
||||
auth,
|
||||
rentNumber,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Tx:", tx.Hash().Hex(), "\n")
|
||||
}
|
||||
|
||||
func chainGet(category string, splited []string) {
|
||||
if len(splited) != 2 {
|
||||
fmt.Println("failed: len(splited) != 2\n")
|
||||
return
|
||||
}
|
||||
var (
|
||||
inc = big.NewInt(1)
|
||||
err error
|
||||
num *big.Int
|
||||
jsonData []byte
|
||||
)
|
||||
switch category {
|
||||
case "estates":
|
||||
num, err = Instance.GetEstatesNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
case "presents":
|
||||
num, err = Instance.GetPresentsNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
case "sales":
|
||||
num, err = Instance.GetSalesNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
case "rents":
|
||||
num, err = Instance.GetRentsNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
default:
|
||||
fmt.Println("undefined category\n")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
for index := big.NewInt(0); index.Cmp(num) == -1; index.Add(index, inc) {
|
||||
switch category {
|
||||
case "estates":
|
||||
data := getEstates(index)
|
||||
if data == nil {
|
||||
fmt.Println("data is nil\n")
|
||||
return
|
||||
}
|
||||
if splited[1] == "my" && User.AddressHex != data.Owner.Hex() {
|
||||
continue
|
||||
}
|
||||
if splited[1] != "all" && splited[1] != "my" &&
|
||||
strings.ToLower(splited[1]) != strings.ToLower(data.Owner.Hex()) {
|
||||
continue
|
||||
}
|
||||
jsonData, err = json.MarshalIndent(data, "", "\t")
|
||||
case "presents":
|
||||
data := getPresents(index)
|
||||
if data == nil {
|
||||
fmt.Println("data is nil\n")
|
||||
return
|
||||
}
|
||||
if data.Finished {
|
||||
continue
|
||||
}
|
||||
if splited[1] == "my" &&
|
||||
(User.AddressHex != data.AddressFrom.Hex() && User.AddressHex != data.AddressTo.Hex()){
|
||||
continue
|
||||
}
|
||||
if splited[1] != "all" && splited[1] != "my" &&
|
||||
(strings.ToLower(splited[1]) != strings.ToLower(data.AddressFrom.Hex()) &&
|
||||
strings.ToLower(splited[1]) != strings.ToLower(data.AddressTo.Hex())) {
|
||||
continue
|
||||
}
|
||||
jsonData, err = json.MarshalIndent(data, "", "\t")
|
||||
case "sales":
|
||||
data := getSales(index)
|
||||
if data == nil {
|
||||
fmt.Println("data is nil\n")
|
||||
return
|
||||
}
|
||||
if data.Finished {
|
||||
continue
|
||||
}
|
||||
if splited[1] == "my" && User.AddressHex != data.Owner.Hex() {
|
||||
continue
|
||||
}
|
||||
if splited[1] != "all" && splited[1] != "my" &&
|
||||
strings.ToLower(splited[1]) != strings.ToLower(data.Owner.Hex()) {
|
||||
continue
|
||||
}
|
||||
jsonData, err = json.MarshalIndent(data, "", "\t")
|
||||
case "rents":
|
||||
data := getRents(index)
|
||||
if data == nil {
|
||||
fmt.Println("data is nil\n")
|
||||
return
|
||||
}
|
||||
if data.Finished {
|
||||
continue
|
||||
}
|
||||
if splited[1] == "my" &&
|
||||
(User.AddressHex != data.Owner.Hex() && User.AddressHex != data.Renter.Hex()){
|
||||
continue
|
||||
}
|
||||
if splited[1] != "all" && splited[1] != "my" &&
|
||||
(strings.ToLower(splited[1]) != strings.ToLower(data.Owner.Hex()) &&
|
||||
strings.ToLower(splited[1]) != strings.ToLower(data.Renter.Hex())) {
|
||||
continue
|
||||
}
|
||||
jsonData, err = json.MarshalIndent(data, "", "\t")
|
||||
default:
|
||||
fmt.Println("undefined category\n")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println(string(jsonData))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func userAddress() {
|
||||
fmt.Println("Address:", User.AddressHex, "\n")
|
||||
}
|
||||
|
||||
func userPurse() {
|
||||
fmt.Println("Purse:", User.Purse, "\n")
|
||||
}
|
||||
|
||||
func userBalance() {
|
||||
balance, err := ClientETH.BalanceAt(context.Background(), User.AddressEth, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err, "\n")
|
||||
return
|
||||
}
|
||||
fmt.Println("Balance:", balance, "\n")
|
||||
}
|
||||
|
||||
func inputString(begin string) string {
|
||||
fmt.Print(begin)
|
||||
msg, _ := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
return strings.Replace(msg, "\n", "", 1)
|
||||
}
|
||||
304
cmd/client_eth/values_eth.go
Normal file
304
cmd/client_eth/values_eth.go
Normal file
@ -0,0 +1,304 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
contract "blockchain-from-scratch/contracts"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
type UserType struct {
|
||||
Purse string
|
||||
AddressHex string
|
||||
AddressEth common.Address
|
||||
PublicKey *ecdsa.PublicKey
|
||||
PrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
type Estate struct {
|
||||
Id *big.Int
|
||||
Owner common.Address
|
||||
Info string
|
||||
Squere *big.Int
|
||||
UsefulSquere *big.Int
|
||||
RenterAddress common.Address
|
||||
PresentStatus bool
|
||||
SaleStatus bool
|
||||
RentStatus bool
|
||||
}
|
||||
|
||||
type Present struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
AddressFrom common.Address
|
||||
AddressTo common.Address
|
||||
Finished bool
|
||||
}
|
||||
|
||||
type Sale struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner common.Address
|
||||
Price *big.Int
|
||||
Customers []common.Address
|
||||
Prices []*big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
type Rent struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner common.Address
|
||||
Renter common.Address
|
||||
Time *big.Int
|
||||
Money *big.Int
|
||||
DeadLine *big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
var (
|
||||
User *UserType
|
||||
ClientETH = connectToETH("http://127.0.0.1:5555")
|
||||
Instance = newContract(
|
||||
common.HexToAddress(readFile("contract.address")),
|
||||
ClientETH,
|
||||
)
|
||||
)
|
||||
|
||||
func loadUser(purse string) *UserType {
|
||||
priv, err := crypto.HexToECDSA(purse)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pub, ok := priv.Public().(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
addressHex := crypto.PubkeyToAddress(*pub).Hex()
|
||||
addressEth := common.HexToAddress(addressHex)
|
||||
return &UserType{
|
||||
Purse: purse,
|
||||
AddressHex: addressHex,
|
||||
AddressEth: addressEth,
|
||||
PublicKey: pub,
|
||||
PrivateKey: priv,
|
||||
}
|
||||
}
|
||||
|
||||
func newContract(contractAddr common.Address, clientEth *ethclient.Client) *contract.Contract {
|
||||
instance, err := contract.NewContract(contractAddr, clientEth)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
func connectToETH(address string) *ethclient.Client {
|
||||
client, err := ethclient.Dial(address)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func readFile(filename string) string {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func resetAuth(user *UserType) *bind.TransactOpts {
|
||||
nonce, err := ClientETH.PendingNonceAt(context.Background(), crypto.PubkeyToAddress(*user.PublicKey))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gasPrice, err := ClientETH.SuggestGasPrice(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
auth := bind.NewKeyedTransactor(user.PrivateKey)
|
||||
auth.Nonce = big.NewInt(int64(nonce))
|
||||
auth.Value = big.NewInt(0)
|
||||
|
||||
auth.GasLimit = uint64(3000000)
|
||||
auth.GasPrice = gasPrice
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func getEstates(index *big.Int) *Estate {
|
||||
// (*big.Int, common.Address, string, *big.Int, *big.Int, common.Address, error)
|
||||
id, owner, info, squere, usefulsquere, renteraddress, err := Instance.GetEstates(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
presentS, saleS, rentS, err := Instance.GetEstatesStatuses(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Estate{
|
||||
Id: id,
|
||||
Owner: owner,
|
||||
Info: info,
|
||||
Squere: squere,
|
||||
UsefulSquere: usefulsquere,
|
||||
RenterAddress: renteraddress,
|
||||
PresentStatus: presentS,
|
||||
SaleStatus: saleS,
|
||||
RentStatus: rentS,
|
||||
}
|
||||
}
|
||||
|
||||
func getPresents(index *big.Int) *Present {
|
||||
// (*big.Int, common.Address, common.Address, bool, error)
|
||||
id, from, to, finished, err := Instance.GetPresents(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Present{
|
||||
Id: index,
|
||||
EstateId: id,
|
||||
AddressFrom: from,
|
||||
AddressTo: to,
|
||||
Finished: finished,
|
||||
}
|
||||
}
|
||||
|
||||
func getSales(index *big.Int) *Sale {
|
||||
// (*big.Int, common.Address, *big.Int, []common.Address, []*big.Int, bool, error)
|
||||
id, owner, price, customers, prices, finished, err := Instance.GetSales(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Sale{
|
||||
Id: index,
|
||||
EstateId: id,
|
||||
Owner: owner,
|
||||
Price: price,
|
||||
Customers: customers,
|
||||
Prices: prices,
|
||||
Finished: finished,
|
||||
}
|
||||
}
|
||||
|
||||
func getRents(index *big.Int) *Rent {
|
||||
// (*big.Int, common.Address, common.Address, *big.Int, *big.Int, *big.Int, bool, error)
|
||||
id, owner, renter, time, money, deadline, finished, err := Instance.GetRents(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Rent{
|
||||
Id: index,
|
||||
EstateId: id,
|
||||
Owner: owner,
|
||||
Renter: renter,
|
||||
Time: time,
|
||||
Money: money,
|
||||
DeadLine: deadline,
|
||||
Finished: finished,
|
||||
}
|
||||
}
|
||||
|
||||
type EstateStr struct {
|
||||
Id *big.Int
|
||||
Owner string
|
||||
Info string
|
||||
Squere *big.Int
|
||||
UsefulSquere *big.Int
|
||||
RenterAddress string
|
||||
PresentStatus bool
|
||||
SaleStatus bool
|
||||
RentStatus bool
|
||||
}
|
||||
|
||||
func estatesToString(estate *Estate) *EstateStr {
|
||||
return &EstateStr{
|
||||
Id: estate.Id,
|
||||
Owner: estate.Owner.Hex(),
|
||||
Info: estate.Info,
|
||||
Squere: estate.Squere,
|
||||
UsefulSquere: estate.UsefulSquere,
|
||||
RenterAddress: estate.RenterAddress.Hex(),
|
||||
PresentStatus: estate.PresentStatus,
|
||||
SaleStatus: estate.SaleStatus,
|
||||
RentStatus: estate.RentStatus,
|
||||
}
|
||||
}
|
||||
|
||||
type PresentStr struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
AddressFrom string
|
||||
AddressTo string
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func presentsToString(present *Present) *PresentStr {
|
||||
return &PresentStr{
|
||||
Id: present.Id,
|
||||
EstateId: present.EstateId,
|
||||
AddressFrom: present.AddressFrom.Hex(),
|
||||
AddressTo: present.AddressTo.Hex(),
|
||||
Finished: present.Finished,
|
||||
}
|
||||
}
|
||||
|
||||
type SaleStr struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner string
|
||||
Price *big.Int
|
||||
Customers []string
|
||||
Prices []*big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func salesToString(sale *Sale) *SaleStr {
|
||||
var customers []string
|
||||
for _, cust := range sale.Customers {
|
||||
customers = append(customers, cust.Hex())
|
||||
}
|
||||
return &SaleStr{
|
||||
Id: sale.Id,
|
||||
EstateId: sale.EstateId,
|
||||
Owner: sale.Owner.Hex(),
|
||||
Price: sale.Price,
|
||||
Customers: customers,
|
||||
Prices: sale.Prices,
|
||||
Finished: sale.Finished,
|
||||
}
|
||||
}
|
||||
|
||||
type RentStr struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner string
|
||||
Renter string
|
||||
Time *big.Int
|
||||
Money *big.Int
|
||||
DeadLine *big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func rentsToString(rent *Rent) *RentStr {
|
||||
return &RentStr{
|
||||
Id: rent.Id,
|
||||
EstateId: rent.EstateId,
|
||||
Owner: rent.Owner.Hex(),
|
||||
Renter: rent.Renter.Hex(),
|
||||
Time: rent.Time,
|
||||
Money: rent.Money,
|
||||
DeadLine: rent.DeadLine,
|
||||
Finished: rent.Finished,
|
||||
}
|
||||
}
|
||||
136
cmd/deploy/deploy.go
Normal file
136
cmd/deploy/deploy.go
Normal file
@ -0,0 +1,136 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
contract "blockchain-from-scratch/contracts"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
type UserType struct {
|
||||
Purse string
|
||||
AddressHex string
|
||||
AddressEth common.Address
|
||||
PublicKey *ecdsa.PublicKey
|
||||
PrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
var (
|
||||
ClientETH = connectToETH("http://127.0.0.1:5555")
|
||||
User *UserType
|
||||
)
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 {
|
||||
panic("failed: len(os.Args) < 2")
|
||||
}
|
||||
var (
|
||||
userLoadStr = ""
|
||||
userLoadExist = false
|
||||
)
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
arg := os.Args[i]
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "-loaduser:"):
|
||||
userLoadStr = strings.Replace(arg, "-loaduser:", "", 1)
|
||||
userLoadExist = true
|
||||
}
|
||||
}
|
||||
if !userLoadExist {
|
||||
panic("failed: !userLoadExist")
|
||||
}
|
||||
if ClientETH == nil {
|
||||
panic("failed: connect to ETH")
|
||||
}
|
||||
User = userLoad(userLoadStr)
|
||||
if User == nil {
|
||||
panic("failed: load user")
|
||||
}
|
||||
}
|
||||
|
||||
// Deploy contract and save address in file.
|
||||
func main() {
|
||||
auth := resetAuth(User)
|
||||
address, tx, instance, err := contract.DeployContract(auth, ClientETH)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(address.Hex())
|
||||
fmt.Println(tx.Hash().Hex())
|
||||
_ = instance
|
||||
|
||||
contractFile := "contract.address"
|
||||
writeFile(contractFile, address.Hex())
|
||||
}
|
||||
|
||||
func writeFile(filename string, data string) error {
|
||||
return ioutil.WriteFile(filename, []byte(data), 0644)
|
||||
}
|
||||
|
||||
func userLoad(purse string) *UserType {
|
||||
priv, err := crypto.HexToECDSA(purse)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pub, ok := priv.Public().(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
addressHex := crypto.PubkeyToAddress(*pub).Hex()
|
||||
addressEth := common.HexToAddress(addressHex)
|
||||
return &UserType{
|
||||
Purse: purse,
|
||||
AddressHex: addressHex,
|
||||
AddressEth: addressEth,
|
||||
PublicKey: pub,
|
||||
PrivateKey: priv,
|
||||
}
|
||||
}
|
||||
|
||||
func connectToETH(address string) *ethclient.Client {
|
||||
client, err := ethclient.Dial(address)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func resetAuth(user *UserType) *bind.TransactOpts {
|
||||
nonce, err := ClientETH.PendingNonceAt(context.Background(), User.AddressEth)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gasPrice, err := ClientETH.SuggestGasPrice(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
auth := bind.NewKeyedTransactor(user.PrivateKey)
|
||||
auth.Nonce = big.NewInt(int64(nonce))
|
||||
auth.Value = big.NewInt(0)
|
||||
|
||||
// auth.GasLimit = uint64(3000000)
|
||||
auth.GasPrice = gasPrice
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func fileIsExist(name string) bool {
|
||||
if _, err := os.Stat(name); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
285
cmd/gclient/gclient.go
Normal file
285
cmd/gclient/gclient.go
Normal file
@ -0,0 +1,285 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
nt "blockchain-from-scratch/network"
|
||||
)
|
||||
|
||||
const (
|
||||
STTC_PATH = "static/"
|
||||
TMPL_PATH = "templates/"
|
||||
ADDR_FILE = "addr.json"
|
||||
)
|
||||
|
||||
func init() {
|
||||
err := json.Unmarshal([]byte(readFile(ADDR_FILE)), &Addresses)
|
||||
if err != nil {
|
||||
panic("failed: load addresses")
|
||||
}
|
||||
if len(Addresses) == 0 {
|
||||
panic("failed: len(Addresses) == 0")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Server is running ...")
|
||||
|
||||
http.Handle("/static/", http.StripPrefix(
|
||||
"/static/",
|
||||
handleFileServer(http.Dir(STTC_PATH))),
|
||||
)
|
||||
|
||||
http.HandleFunc("/", indexPage)
|
||||
http.HandleFunc("/login", loginPage)
|
||||
http.HandleFunc("/signup", signupPage)
|
||||
http.HandleFunc("/logout", logoutPage)
|
||||
http.HandleFunc("/account", accountPage)
|
||||
http.HandleFunc("/transaction", transactionPage)
|
||||
http.HandleFunc("/blockchain", blockchainPage)
|
||||
http.HandleFunc("/blockchain/", blockchainXPage)
|
||||
|
||||
http.ListenAndServe(":7545", nil)
|
||||
}
|
||||
|
||||
func handleFileServer(fs http.FileSystem) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := fs.Open(r.URL.Path); os.IsNotExist(err) {
|
||||
indexPage(w, r)
|
||||
return
|
||||
}
|
||||
http.FileServer(fs).ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func indexPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"index.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
User *bc.User
|
||||
}
|
||||
data.User = User
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func accountPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"account.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
User *bc.User
|
||||
Address string
|
||||
Balance string
|
||||
}
|
||||
data.User = User
|
||||
if data.User != nil {
|
||||
data.Address = User.Address()
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_BLNCE,
|
||||
Data: data.Address,
|
||||
})
|
||||
if res != nil {
|
||||
data.Balance = res.Data
|
||||
}
|
||||
} else {
|
||||
http.Redirect(w, r, "/", 302)
|
||||
return
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func loginPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"login.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
User *bc.User
|
||||
Error string
|
||||
}
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
User = bc.LoadUser(r.FormValue("private"))
|
||||
if User == nil {
|
||||
data.Error = "Load Private Key Error"
|
||||
} else {
|
||||
http.Redirect(w, r, "/", 302)
|
||||
return
|
||||
}
|
||||
}
|
||||
data.User = User
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func logoutPage(w http.ResponseWriter, r *http.Request) {
|
||||
User = nil
|
||||
http.Redirect(w, r, "/", 302)
|
||||
}
|
||||
|
||||
func signupPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"signup.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
User *bc.User
|
||||
PrivateKey string
|
||||
}
|
||||
data.User = User
|
||||
if r.Method == "POST" {
|
||||
data.PrivateKey = bc.NewUser().Purse()
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func transactionPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"transaction.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
User *bc.User
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
if data.User == nil {
|
||||
data.Error = "User not authorizated"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
receiver := r.FormValue("receiver")
|
||||
num, err := strconv.Atoi(r.FormValue("value"))
|
||||
if err != nil {
|
||||
data.Error = "strconv.Atoi error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
flag := false
|
||||
for _, addr := range Addresses {
|
||||
res := nt.Send(addr, &nt.Package{
|
||||
Option: GET_LHASH,
|
||||
})
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
tx := bc.NewTransaction(User, bc.Base64Decode(res.Data), receiver, uint64(num))
|
||||
res = nt.Send(addr, &nt.Package{
|
||||
Option: ADD_TRNSX,
|
||||
Data: bc.SerializeTX(tx),
|
||||
})
|
||||
if res == nil || res.Data != "ok" {
|
||||
continue
|
||||
}
|
||||
flag = true
|
||||
}
|
||||
if !flag {
|
||||
data.Error = "TX failed"
|
||||
} else {
|
||||
data.Error = "TX success"
|
||||
}
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"blockchain.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
Error string
|
||||
Size []bool
|
||||
Address string
|
||||
Balance string
|
||||
User *bc.User
|
||||
}
|
||||
data.User = User
|
||||
if r.Method == "POST" {
|
||||
data.Address = r.FormValue("address")
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_BLNCE,
|
||||
Data: data.Address,
|
||||
})
|
||||
if res != nil {
|
||||
data.Balance = res.Data
|
||||
}
|
||||
}
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_CSIZE,
|
||||
})
|
||||
if res == nil || res.Data == "" {
|
||||
data.Error = "Receive error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
num, err := strconv.Atoi(res.Data)
|
||||
if err != nil {
|
||||
data.Error = "strconv.Atoi error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Size = make([]bool, num)
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainXPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"blockchainX.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct {
|
||||
Error string
|
||||
Block *bc.Block
|
||||
User *bc.User
|
||||
}
|
||||
data.User = User
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_BLOCK,
|
||||
Data: strings.Replace(r.URL.Path, "/blockchain/", "", 1),
|
||||
})
|
||||
if res == nil || res.Data == "" {
|
||||
data.Error = "Receive error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = bc.DeserializeBlock(res.Data)
|
||||
if data.Block == nil {
|
||||
data.Error = "Block is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
60
cmd/gclient/values.go
Normal file
60
cmd/gclient/values.go
Normal file
@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var (
|
||||
Addresses []string
|
||||
User *bc.User
|
||||
)
|
||||
|
||||
const (
|
||||
SEPARATOR = "_SEPARATOR_"
|
||||
)
|
||||
|
||||
const (
|
||||
ADD_BLOCK = iota + 1
|
||||
ADD_TRNSX
|
||||
GET_BLOCK
|
||||
GET_LHASH
|
||||
GET_BLNCE
|
||||
GET_CSIZE
|
||||
)
|
||||
|
||||
func userNew(filename string) *bc.User {
|
||||
user := bc.NewUser()
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
err := writeFile(filename, user.Purse())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func userLoad(filename string) *bc.User {
|
||||
priv := readFile(filename)
|
||||
if priv == "" {
|
||||
return nil
|
||||
}
|
||||
user := bc.LoadUser(priv)
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func writeFile(filename string, data string) error {
|
||||
return ioutil.WriteFile(filename, []byte(data), 0644)
|
||||
}
|
||||
|
||||
func readFile(filename string) string {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
905
cmd/gclient_eth/gclient_eth.go
Normal file
905
cmd/gclient_eth/gclient_eth.go
Normal file
@ -0,0 +1,905 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"strings"
|
||||
"context"
|
||||
"net/http"
|
||||
"math/big"
|
||||
"html/template"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const (
|
||||
STTC_PATH = "static/"
|
||||
TMPL_PATH = "templates_eth/"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if ClientETH == nil {
|
||||
panic("failed: connect to ETH")
|
||||
}
|
||||
if Instance == nil {
|
||||
panic("failed: instance is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Server is running ...")
|
||||
|
||||
http.Handle("/static/", http.StripPrefix(
|
||||
"/static/",
|
||||
handleFileServer(http.Dir(STTC_PATH))),
|
||||
)
|
||||
|
||||
http.HandleFunc("/", indexPage)
|
||||
http.HandleFunc("/login", loginPage)
|
||||
http.HandleFunc("/logout", logoutPage)
|
||||
http.HandleFunc("/account", accountPage)
|
||||
|
||||
http.HandleFunc("/blockchain", blockchainPage)
|
||||
http.HandleFunc("/blockchain/estates", blockchainEstatesPage)
|
||||
http.HandleFunc("/blockchain/presents", blockchainPresentsPage)
|
||||
http.HandleFunc("/blockchain/sales", blockchainSalesPage)
|
||||
http.HandleFunc("/blockchain/rents", blockchainRentsPage)
|
||||
|
||||
http.HandleFunc("/blockchain/estates/", blockchainEstatesXPage)
|
||||
http.HandleFunc("/blockchain/presents/", blockchainPresentsXPage)
|
||||
http.HandleFunc("/blockchain/sales/", blockchainSalesXPage)
|
||||
http.HandleFunc("/blockchain/rents/", blockchainRentsXPage)
|
||||
|
||||
http.HandleFunc("/blockchain/presents/do/", blockchainPresentsDoPage)
|
||||
http.HandleFunc("/blockchain/sales/do/", blockchainSalesDoPage)
|
||||
http.HandleFunc("/blockchain/rents/do/", blockchainRentsDoPage)
|
||||
|
||||
http.ListenAndServe(":7545", nil)
|
||||
}
|
||||
|
||||
func handleFileServer(fs http.FileSystem) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := fs.Open(r.URL.Path); os.IsNotExist(err) {
|
||||
indexPage(w, r)
|
||||
return
|
||||
}
|
||||
http.FileServer(fs).ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func indexPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"index.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
}
|
||||
data.User = User
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func loginPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"login.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Error string
|
||||
}
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
User = loadUser(r.FormValue("private"))
|
||||
if User == nil {
|
||||
data.Error = "Load Private Key Error"
|
||||
} else {
|
||||
http.Redirect(w, r, "/", 302)
|
||||
return
|
||||
}
|
||||
}
|
||||
data.User = User
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func logoutPage(w http.ResponseWriter, r *http.Request) {
|
||||
User = nil
|
||||
http.Redirect(w, r, "/", 302)
|
||||
}
|
||||
|
||||
func accountPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"account.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Address string
|
||||
Balance string
|
||||
}
|
||||
data.User = User
|
||||
if data.User != nil {
|
||||
data.Address = User.AddressHex
|
||||
balance, err := ClientETH.BalanceAt(context.Background(), User.AddressEth, nil)
|
||||
if err == nil {
|
||||
data.Balance = balance.String()
|
||||
}
|
||||
} else {
|
||||
http.Redirect(w, r, "/", 302)
|
||||
return
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainPresentsDoPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"presentsDo.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *EstateStr
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/presents/do/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
estate := getEstates(index)
|
||||
if estate == nil {
|
||||
data.Error = "estate is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = estatesToString(estate)
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
_, err := Instance.CreatePresent(
|
||||
resetAuth(User),
|
||||
index,
|
||||
common.HexToAddress(r.FormValue("address")),
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success created"
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainSalesDoPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"salesDo.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *EstateStr
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/sales/do/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
estate := getEstates(index)
|
||||
if estate == nil {
|
||||
data.Error = "estate is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = estatesToString(estate)
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
var (
|
||||
price = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
price, ok = price.SetString(r.FormValue("price"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
_, err := Instance.CreateSale(
|
||||
resetAuth(User),
|
||||
index,
|
||||
price,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success created"
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainRentsDoPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"rentsDo.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *EstateStr
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/rents/do/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
rent := getEstates(index)
|
||||
if rent == nil {
|
||||
data.Error = "rent is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = estatesToString(rent)
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
var (
|
||||
days = new(big.Int)
|
||||
price = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
days, ok = days.SetString(r.FormValue("days"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
price, ok = price.SetString(r.FormValue("price"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
_, err := Instance.CreateRent(
|
||||
resetAuth(User),
|
||||
index,
|
||||
days,
|
||||
price,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success created"
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainEstatesXPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"estatesX.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *EstateStr
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/estates/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
estate := getEstates(index)
|
||||
if estate == nil {
|
||||
data.Error = "estate is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = estatesToString(estate)
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainPresentsXPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"presentsX.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *PresentStr
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/presents/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
present := getPresents(index)
|
||||
if present == nil {
|
||||
data.Error = "present is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = presentsToString(present)
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
if r.FormValue("cancel") != "" {
|
||||
_, err := Instance.CancelPresent(
|
||||
resetAuth(User),
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success cancel"
|
||||
}
|
||||
if r.FormValue("confirm") != "" {
|
||||
_, err := Instance.ConfirmPresent(
|
||||
resetAuth(User),
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success confirm"
|
||||
}
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainSalesXPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"salesX.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *SaleStr
|
||||
Error string
|
||||
InCustomers bool
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/sales/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
sale := getSales(index)
|
||||
if sale == nil {
|
||||
data.Error = "sale is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = salesToString(sale)
|
||||
for _, cust := range data.Block.Customers {
|
||||
if cust == User.AddressHex {
|
||||
data.InCustomers = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
if r.FormValue("cancel") != "" {
|
||||
_, err := Instance.CancelSale(
|
||||
resetAuth(User),
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success cancel"
|
||||
}
|
||||
if r.FormValue("confirm") != "" {
|
||||
var (
|
||||
saleTo = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
saleTo, ok = saleTo.SetString(r.FormValue("addrnum"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
_, err := Instance.ConfirmSale(
|
||||
resetAuth(User),
|
||||
index,
|
||||
saleTo,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success confirm"
|
||||
}
|
||||
if r.FormValue("buy") != "" {
|
||||
var (
|
||||
price = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
price, ok = price.SetString(r.FormValue("price"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
auth := resetAuth(User)
|
||||
if auth == nil {
|
||||
data.Error = "failed: auth is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
auth.Value = price
|
||||
_, err := Instance.CheckToBuy(
|
||||
auth,
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success buy request"
|
||||
}
|
||||
if r.FormValue("close") != "" {
|
||||
_, err := Instance.CancelToBuy(
|
||||
resetAuth(User),
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success close buy request"
|
||||
}
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainRentsXPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"rentsX.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
Block *RentStr
|
||||
Error string
|
||||
Confirmed bool
|
||||
}
|
||||
data.User = User
|
||||
var (
|
||||
index = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
num := strings.Replace(r.URL.Path, "/blockchain/rents/", "", 1)
|
||||
index, ok = index.SetString(num, 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
rent := getRents(index)
|
||||
if rent == nil {
|
||||
data.Error = "rent is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Block = rentsToString(rent)
|
||||
if data.Block.Renter != "0x0000000000000000000000000000000000000000" {
|
||||
data.Confirmed = true
|
||||
}
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
if r.FormValue("cancel") != "" {
|
||||
_, err := Instance.CancelRent(
|
||||
resetAuth(User),
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success cancel"
|
||||
}
|
||||
if r.FormValue("confirm") != "" {
|
||||
auth := resetAuth(User)
|
||||
if auth == nil {
|
||||
data.Error = "failed: auth is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
auth.Value = rent.Money
|
||||
_, err := Instance.ToRent(
|
||||
auth,
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success confirm"
|
||||
}
|
||||
if r.FormValue("finish") != "" {
|
||||
_, err := Instance.FinishRent(
|
||||
resetAuth(User),
|
||||
index,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success finish"
|
||||
}
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"blockchain.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
User *UserType
|
||||
IsAdmin bool
|
||||
Error string
|
||||
}
|
||||
data.User = User
|
||||
iamAdmin, err := Instance.IamAdmin(&bind.CallOpts{From: User.AddressEth})
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
if iamAdmin {
|
||||
data.IsAdmin = true
|
||||
}
|
||||
if r.Method == "POST" {
|
||||
r.ParseForm()
|
||||
var (
|
||||
squere = new(big.Int)
|
||||
usefulSquere = new(big.Int)
|
||||
ok bool
|
||||
)
|
||||
squere, ok = squere.SetString(r.FormValue("squere"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error 1"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
usefulSquere, ok = usefulSquere.SetString(r.FormValue("usefulsquere"), 10)
|
||||
if !ok {
|
||||
data.Error = "strconv error 2"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
_, err := Instance.CreateEstate(
|
||||
resetAuth(User),
|
||||
User.AddressEth,
|
||||
r.FormValue("info"),
|
||||
squere,
|
||||
usefulSquere,
|
||||
)
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
data.Error = "Success created"
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainEstatesPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"estates.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
Error string
|
||||
Blocks []uint64
|
||||
Address string
|
||||
User *UserType
|
||||
}
|
||||
data.User = User
|
||||
data.Address = User.AddressHex
|
||||
if r.Method == "POST" {
|
||||
data.Address = r.FormValue("address")
|
||||
}
|
||||
var inc = big.NewInt(1)
|
||||
num, err := Instance.GetEstatesNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
for index := big.NewInt(0); index.Cmp(num) == -1; index.Add(index, inc) {
|
||||
block := getEstates(index)
|
||||
if block == nil {
|
||||
data.Error = "data is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
if data.Address != "all" && strings.ToLower(data.Address) != strings.ToLower(block.Owner.Hex()) {
|
||||
continue
|
||||
}
|
||||
data.Blocks = append(data.Blocks, index.Uint64())
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainPresentsPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"presents.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
Error string
|
||||
Blocks []uint64
|
||||
Address string
|
||||
User *UserType
|
||||
}
|
||||
data.User = User
|
||||
data.Address = User.AddressHex
|
||||
if r.Method == "POST" {
|
||||
data.Address = r.FormValue("address")
|
||||
}
|
||||
var inc = big.NewInt(1)
|
||||
num, err := Instance.GetPresentsNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
for index := big.NewInt(0); index.Cmp(num) == -1; index.Add(index, inc) {
|
||||
block := getPresents(index)
|
||||
if block == nil {
|
||||
data.Error = "data is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
if block.Finished {
|
||||
continue
|
||||
}
|
||||
if data.Address != "all" &&
|
||||
strings.ToLower(data.Address) != strings.ToLower(block.AddressFrom.Hex()) &&
|
||||
strings.ToLower(data.Address) != strings.ToLower(block.AddressTo.Hex()) {
|
||||
continue
|
||||
}
|
||||
data.Blocks = append(data.Blocks, index.Uint64())
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainSalesPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"sales.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
Error string
|
||||
Blocks []uint64
|
||||
Address string
|
||||
User *UserType
|
||||
}
|
||||
data.User = User
|
||||
data.Address = User.AddressHex
|
||||
if r.Method == "POST" {
|
||||
data.Address = r.FormValue("address")
|
||||
}
|
||||
var inc = big.NewInt(1)
|
||||
num, err := Instance.GetSalesNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
for index := big.NewInt(0); index.Cmp(num) == -1; index.Add(index, inc) {
|
||||
block := getSales(index)
|
||||
if block == nil {
|
||||
data.Error = "data is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
if block.Finished {
|
||||
continue
|
||||
}
|
||||
if data.Address != "all" &&
|
||||
strings.ToLower(data.Address) != strings.ToLower(block.Owner.Hex()) {
|
||||
continue
|
||||
}
|
||||
data.Blocks = append(data.Blocks, index.Uint64())
|
||||
}
|
||||
t.Execute(w, data)
|
||||
}
|
||||
|
||||
func blockchainRentsPage(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles(
|
||||
TMPL_PATH+"base.html",
|
||||
TMPL_PATH+"rents.html",
|
||||
)
|
||||
if err != nil {
|
||||
panic("can't load hmtl files")
|
||||
}
|
||||
if User == nil {
|
||||
http.Redirect(w, r, "/login", 302)
|
||||
return
|
||||
}
|
||||
var data struct{
|
||||
Error string
|
||||
Blocks []uint64
|
||||
Address string
|
||||
User *UserType
|
||||
}
|
||||
data.User = User
|
||||
data.Address = User.AddressHex
|
||||
if r.Method == "POST" {
|
||||
data.Address = r.FormValue("address")
|
||||
}
|
||||
var inc = big.NewInt(1)
|
||||
num, err := Instance.GetRentsNumber(&bind.CallOpts{From: User.AddressEth})
|
||||
if err != nil {
|
||||
data.Error = err.Error()
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
for index := big.NewInt(0); index.Cmp(num) == -1; index.Add(index, inc) {
|
||||
block := getRents(index)
|
||||
if block == nil {
|
||||
data.Error = "data is nil"
|
||||
t.Execute(w, data)
|
||||
return
|
||||
}
|
||||
if block.Finished {
|
||||
continue
|
||||
}
|
||||
if data.Address != "all" &&
|
||||
strings.ToLower(data.Address) != strings.ToLower(block.Owner.Hex()) &&
|
||||
strings.ToLower(data.Address) != strings.ToLower(block.Renter.Hex()) {
|
||||
continue
|
||||
}
|
||||
data.Blocks = append(data.Blocks, index.Uint64())
|
||||
}
|
||||
|
||||
t.Execute(w, data)
|
||||
}
|
||||
304
cmd/gclient_eth/values_eth.go
Normal file
304
cmd/gclient_eth/values_eth.go
Normal file
@ -0,0 +1,304 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
contract "blockchain-from-scratch/contracts"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
type UserType struct {
|
||||
Purse string
|
||||
AddressHex string
|
||||
AddressEth common.Address
|
||||
PublicKey *ecdsa.PublicKey
|
||||
PrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
type Estate struct {
|
||||
Id *big.Int
|
||||
Owner common.Address
|
||||
Info string
|
||||
Squere *big.Int
|
||||
UsefulSquere *big.Int
|
||||
RenterAddress common.Address
|
||||
PresentStatus bool
|
||||
SaleStatus bool
|
||||
RentStatus bool
|
||||
}
|
||||
|
||||
type Present struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
AddressFrom common.Address
|
||||
AddressTo common.Address
|
||||
Finished bool
|
||||
}
|
||||
|
||||
type Sale struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner common.Address
|
||||
Price *big.Int
|
||||
Customers []common.Address
|
||||
Prices []*big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
type Rent struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner common.Address
|
||||
Renter common.Address
|
||||
Time *big.Int
|
||||
Money *big.Int
|
||||
DeadLine *big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
var (
|
||||
User *UserType
|
||||
ClientETH = connectToETH("http://127.0.0.1:5555")
|
||||
Instance = newContract(
|
||||
common.HexToAddress(readFile("contract.address")),
|
||||
ClientETH,
|
||||
)
|
||||
)
|
||||
|
||||
func loadUser(purse string) *UserType {
|
||||
priv, err := crypto.HexToECDSA(purse)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pub, ok := priv.Public().(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
addressHex := crypto.PubkeyToAddress(*pub).Hex()
|
||||
addressEth := common.HexToAddress(addressHex)
|
||||
return &UserType{
|
||||
Purse: purse,
|
||||
AddressHex: addressHex,
|
||||
AddressEth: addressEth,
|
||||
PublicKey: pub,
|
||||
PrivateKey: priv,
|
||||
}
|
||||
}
|
||||
|
||||
func newContract(contractAddr common.Address, clientEth *ethclient.Client) *contract.Contract {
|
||||
instance, err := contract.NewContract(contractAddr, clientEth)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
func connectToETH(address string) *ethclient.Client {
|
||||
client, err := ethclient.Dial(address)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func readFile(filename string) string {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func resetAuth(user *UserType) *bind.TransactOpts {
|
||||
nonce, err := ClientETH.PendingNonceAt(context.Background(), crypto.PubkeyToAddress(*user.PublicKey))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gasPrice, err := ClientETH.SuggestGasPrice(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
auth := bind.NewKeyedTransactor(user.PrivateKey)
|
||||
auth.Nonce = big.NewInt(int64(nonce))
|
||||
auth.Value = big.NewInt(0)
|
||||
|
||||
auth.GasLimit = uint64(3000000)
|
||||
auth.GasPrice = gasPrice
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
func getEstates(index *big.Int) *Estate {
|
||||
// (*big.Int, common.Address, string, *big.Int, *big.Int, common.Address, error)
|
||||
id, owner, info, squere, usefulsquere, renteraddress, err := Instance.GetEstates(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
presentS, saleS, rentS, err := Instance.GetEstatesStatuses(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Estate{
|
||||
Id: id,
|
||||
Owner: owner,
|
||||
Info: info,
|
||||
Squere: squere,
|
||||
UsefulSquere: usefulsquere,
|
||||
RenterAddress: renteraddress,
|
||||
PresentStatus: presentS,
|
||||
SaleStatus: saleS,
|
||||
RentStatus: rentS,
|
||||
}
|
||||
}
|
||||
|
||||
func getPresents(index *big.Int) *Present {
|
||||
// (*big.Int, common.Address, common.Address, bool, error)
|
||||
id, from, to, finished, err := Instance.GetPresents(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Present{
|
||||
Id: index,
|
||||
EstateId: id,
|
||||
AddressFrom: from,
|
||||
AddressTo: to,
|
||||
Finished: finished,
|
||||
}
|
||||
}
|
||||
|
||||
func getSales(index *big.Int) *Sale {
|
||||
// (*big.Int, common.Address, *big.Int, []common.Address, []*big.Int, bool, error)
|
||||
id, owner, price, customers, prices, finished, err := Instance.GetSales(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Sale{
|
||||
Id: index,
|
||||
EstateId: id,
|
||||
Owner: owner,
|
||||
Price: price,
|
||||
Customers: customers,
|
||||
Prices: prices,
|
||||
Finished: finished,
|
||||
}
|
||||
}
|
||||
|
||||
func getRents(index *big.Int) *Rent {
|
||||
// (*big.Int, common.Address, common.Address, *big.Int, *big.Int, *big.Int, bool, error)
|
||||
id, owner, renter, time, money, deadline, finished, err := Instance.GetRents(&bind.CallOpts{From: User.AddressEth}, index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Rent{
|
||||
Id: index,
|
||||
EstateId: id,
|
||||
Owner: owner,
|
||||
Renter: renter,
|
||||
Time: time,
|
||||
Money: money,
|
||||
DeadLine: deadline,
|
||||
Finished: finished,
|
||||
}
|
||||
}
|
||||
|
||||
type EstateStr struct {
|
||||
Id *big.Int
|
||||
Owner string
|
||||
Info string
|
||||
Squere *big.Int
|
||||
UsefulSquere *big.Int
|
||||
RenterAddress string
|
||||
PresentStatus bool
|
||||
SaleStatus bool
|
||||
RentStatus bool
|
||||
}
|
||||
|
||||
func estatesToString(estate *Estate) *EstateStr {
|
||||
return &EstateStr{
|
||||
Id: estate.Id,
|
||||
Owner: estate.Owner.Hex(),
|
||||
Info: estate.Info,
|
||||
Squere: estate.Squere,
|
||||
UsefulSquere: estate.UsefulSquere,
|
||||
RenterAddress: estate.RenterAddress.Hex(),
|
||||
PresentStatus: estate.PresentStatus,
|
||||
SaleStatus: estate.SaleStatus,
|
||||
RentStatus: estate.RentStatus,
|
||||
}
|
||||
}
|
||||
|
||||
type PresentStr struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
AddressFrom string
|
||||
AddressTo string
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func presentsToString(present *Present) *PresentStr {
|
||||
return &PresentStr{
|
||||
Id: present.Id,
|
||||
EstateId: present.EstateId,
|
||||
AddressFrom: present.AddressFrom.Hex(),
|
||||
AddressTo: present.AddressTo.Hex(),
|
||||
Finished: present.Finished,
|
||||
}
|
||||
}
|
||||
|
||||
type SaleStr struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner string
|
||||
Price *big.Int
|
||||
Customers []string
|
||||
Prices []*big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func salesToString(sale *Sale) *SaleStr {
|
||||
var customers []string
|
||||
for _, cust := range sale.Customers {
|
||||
customers = append(customers, cust.Hex())
|
||||
}
|
||||
return &SaleStr{
|
||||
Id: sale.Id,
|
||||
EstateId: sale.EstateId,
|
||||
Owner: sale.Owner.Hex(),
|
||||
Price: sale.Price,
|
||||
Customers: customers,
|
||||
Prices: sale.Prices,
|
||||
Finished: sale.Finished,
|
||||
}
|
||||
}
|
||||
|
||||
type RentStr struct {
|
||||
Id *big.Int
|
||||
EstateId *big.Int
|
||||
Owner string
|
||||
Renter string
|
||||
Time *big.Int
|
||||
Money *big.Int
|
||||
DeadLine *big.Int
|
||||
Finished bool
|
||||
}
|
||||
|
||||
func rentsToString(rent *Rent) *RentStr {
|
||||
return &RentStr{
|
||||
Id: rent.Id,
|
||||
EstateId: rent.EstateId,
|
||||
Owner: rent.Owner.Hex(),
|
||||
Renter: rent.Renter.Hex(),
|
||||
Time: rent.Time,
|
||||
Money: rent.Money,
|
||||
DeadLine: rent.DeadLine,
|
||||
Finished: rent.Finished,
|
||||
}
|
||||
}
|
||||
129
cmd/node/node.go
Normal file
129
cmd/node/node.go
Normal file
@ -0,0 +1,129 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
nt "blockchain-from-scratch/network"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if len(os.Args) < 2 {
|
||||
panic("failed: len(os.Args) < 2")
|
||||
}
|
||||
var (
|
||||
serveStr = ""
|
||||
addrStr = ""
|
||||
userNewStr = ""
|
||||
userLoadStr = ""
|
||||
chainNewStr = ""
|
||||
chainLoadStr = ""
|
||||
)
|
||||
var (
|
||||
serveExist = false
|
||||
addrExist = false
|
||||
userNewExist = false
|
||||
userLoadExist = false
|
||||
chainNewExist = false
|
||||
chainLoadExist = false
|
||||
)
|
||||
for i := 1; i < len(os.Args); i++ {
|
||||
arg := os.Args[i]
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "-serve:"):
|
||||
serveStr = strings.Replace(arg, "-serve:", "", 1)
|
||||
serveExist = true
|
||||
case strings.HasPrefix(arg, "-loadaddr:"):
|
||||
addrStr = strings.Replace(arg, "-loadaddr:", "", 1)
|
||||
addrExist = true
|
||||
case strings.HasPrefix(arg, "-newuser:"):
|
||||
userNewStr = strings.Replace(arg, "-newuser:", "", 1)
|
||||
userNewExist = true
|
||||
case strings.HasPrefix(arg, "-loaduser:"):
|
||||
userLoadStr = strings.Replace(arg, "-loaduser:", "", 1)
|
||||
userLoadExist = true
|
||||
case strings.HasPrefix(arg, "-newchain:"):
|
||||
chainNewStr = strings.Replace(arg, "-newchain:", "", 1)
|
||||
chainNewExist = true
|
||||
case strings.HasPrefix(arg, "-loadchain:"):
|
||||
chainLoadStr = strings.Replace(arg, "-loadchain:", "", 1)
|
||||
chainLoadExist = true
|
||||
}
|
||||
}
|
||||
|
||||
if !(userNewExist || userLoadExist) || !(chainNewExist || chainLoadExist) ||
|
||||
!serveExist || !addrExist {
|
||||
panic("failed: !(userNewExist || userLoadExist)" +
|
||||
"|| !(chainNewExist || chainLoadExist) || !serveExist || !addrExist")
|
||||
}
|
||||
|
||||
Serve = serveStr
|
||||
|
||||
var addresses []string
|
||||
err := json.Unmarshal([]byte(readFile(addrStr)), &addresses)
|
||||
if err != nil {
|
||||
panic("failed: load addresses")
|
||||
}
|
||||
|
||||
var mapaddr = make(map[string]bool)
|
||||
for _, addr := range addresses {
|
||||
if addr == Serve {
|
||||
continue
|
||||
}
|
||||
if _, ok := mapaddr[addr]; ok {
|
||||
continue
|
||||
}
|
||||
mapaddr[addr] = true
|
||||
Addresses = append(Addresses, addr)
|
||||
}
|
||||
|
||||
if userNewExist {
|
||||
User = userNew(userNewStr)
|
||||
}
|
||||
if userLoadExist {
|
||||
User = userLoad(userLoadStr)
|
||||
}
|
||||
if User == nil {
|
||||
panic("failed: load user")
|
||||
}
|
||||
|
||||
if chainNewExist {
|
||||
Filename = chainNewStr
|
||||
Chain = chainNew(chainNewStr)
|
||||
}
|
||||
if chainLoadExist {
|
||||
Filename = chainLoadStr
|
||||
Chain = chainLoad(chainLoadStr)
|
||||
}
|
||||
if Chain == nil {
|
||||
panic("failed: load chain")
|
||||
}
|
||||
|
||||
Block = bc.NewBlock(User.Address(), Chain.LastHash())
|
||||
}
|
||||
|
||||
func main() {
|
||||
nt.Listen(Serve, handleServer)
|
||||
for {
|
||||
fmt.Scanln()
|
||||
}
|
||||
}
|
||||
|
||||
func chainNew(filename string) *bc.BlockChain {
|
||||
err := bc.NewChain(filename, User.Address())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return bc.LoadChain(filename)
|
||||
}
|
||||
|
||||
func chainLoad(filename string) *bc.BlockChain {
|
||||
chain := bc.LoadChain(filename)
|
||||
if chain == nil {
|
||||
return nil
|
||||
}
|
||||
return chain
|
||||
}
|
||||
290
cmd/node/serve.go
Normal file
290
cmd/node/serve.go
Normal file
@ -0,0 +1,290 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
nt "blockchain-from-scratch/network"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var (
|
||||
Filename string
|
||||
Serve string
|
||||
Chain *bc.BlockChain
|
||||
Block *bc.Block
|
||||
Mutex sync.Mutex
|
||||
)
|
||||
|
||||
var (
|
||||
IsMining bool
|
||||
BreakMining = make(chan bool)
|
||||
)
|
||||
|
||||
func handleServer(conn nt.Conn, pack *nt.Package) {
|
||||
nt.Handle(ADD_BLOCK, conn, pack, addBlock)
|
||||
nt.Handle(ADD_TRNSX, conn, pack, addTransaction)
|
||||
nt.Handle(GET_BLOCK, conn, pack, getBlock)
|
||||
nt.Handle(GET_LHASH, conn, pack, getLastHash)
|
||||
nt.Handle(GET_BLNCE, conn, pack, getBalance)
|
||||
nt.Handle(GET_CSIZE, conn, pack, getChainSize)
|
||||
}
|
||||
|
||||
func getChainSize(pack *nt.Package) string {
|
||||
return fmt.Sprintf("%d", Chain.Size())
|
||||
}
|
||||
|
||||
func addBlock(pack *nt.Package) string {
|
||||
splited := strings.Split(pack.Data, SEPARATOR)
|
||||
if len(splited) != 3 {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
block := bc.DeserializeBlock(splited[2])
|
||||
if !block.IsValid(Chain, Chain.Size()) {
|
||||
currSize := Chain.Size()
|
||||
num, err := strconv.Atoi(splited[1])
|
||||
if err != nil {
|
||||
return "fail"
|
||||
}
|
||||
if currSize < uint64(num) {
|
||||
go compareChains(splited[0], uint64(num))
|
||||
return "ok"
|
||||
}
|
||||
return "fail"
|
||||
}
|
||||
|
||||
Mutex.Lock()
|
||||
|
||||
Chain.AddBlock(block)
|
||||
Block = bc.NewBlock(User.Address(), Chain.LastHash())
|
||||
|
||||
Mutex.Unlock()
|
||||
|
||||
if IsMining {
|
||||
BreakMining <- true
|
||||
IsMining = false
|
||||
}
|
||||
|
||||
return "ok"
|
||||
}
|
||||
|
||||
func compareChains(address string, num uint64) {
|
||||
filename := "temp_" + hex.EncodeToString(bc.GenerateRandomBytes(8))
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file.Close()
|
||||
defer func() {
|
||||
os.Remove(filename)
|
||||
}()
|
||||
|
||||
res := nt.Send(address, &nt.Package{
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", 0),
|
||||
})
|
||||
if res == nil {
|
||||
return
|
||||
}
|
||||
|
||||
genesis := bc.DeserializeBlock(res.Data)
|
||||
if genesis == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(genesis.CurrHash, hashBlock(genesis)) {
|
||||
return
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(bc.CREATE_TABLE)
|
||||
chain := &bc.BlockChain{
|
||||
DB: db,
|
||||
}
|
||||
chain.AddBlock(genesis)
|
||||
|
||||
defer func() {
|
||||
chain.DB.Close()
|
||||
}()
|
||||
|
||||
for i := uint64(1); i < num; i++ {
|
||||
res := nt.Send(address, &nt.Package{
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", i),
|
||||
})
|
||||
if res == nil {
|
||||
return
|
||||
}
|
||||
block := bc.DeserializeBlock(res.Data)
|
||||
if block == nil {
|
||||
return
|
||||
}
|
||||
if !block.IsValid(chain, i) {
|
||||
return
|
||||
}
|
||||
chain.AddBlock(block)
|
||||
}
|
||||
|
||||
Mutex.Lock()
|
||||
|
||||
Chain.DB.Close()
|
||||
os.Remove(Filename)
|
||||
|
||||
copyFile(filename, Filename)
|
||||
Chain = bc.LoadChain(Filename)
|
||||
Block = bc.NewBlock(User.Address(), Chain.LastHash())
|
||||
|
||||
Mutex.Unlock()
|
||||
|
||||
if IsMining {
|
||||
BreakMining <- true
|
||||
IsMining = false
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func hashBlock(block *bc.Block) []byte {
|
||||
var tempHash []byte
|
||||
for _, tx := range block.Transactions {
|
||||
tempHash = bc.HashSum(bytes.Join(
|
||||
[][]byte{
|
||||
tempHash,
|
||||
tx.CurrHash,
|
||||
},
|
||||
[]byte{},
|
||||
))
|
||||
}
|
||||
var list []string
|
||||
for hash := range block.Mapping {
|
||||
list = append(list, hash)
|
||||
}
|
||||
sort.Strings(list)
|
||||
for _, hash := range list {
|
||||
tempHash = bc.HashSum(bytes.Join(
|
||||
[][]byte{
|
||||
tempHash,
|
||||
[]byte(hash),
|
||||
bc.ToBytes(block.Mapping[hash]),
|
||||
},
|
||||
[]byte{},
|
||||
))
|
||||
}
|
||||
return bc.HashSum(bytes.Join(
|
||||
[][]byte{
|
||||
tempHash,
|
||||
bc.ToBytes(uint64(block.Difficulty)),
|
||||
block.PrevHash,
|
||||
[]byte(block.Miner),
|
||||
[]byte(block.TimeStamp),
|
||||
},
|
||||
[]byte{},
|
||||
))
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return out.Close()
|
||||
}
|
||||
|
||||
func getBlock(pack *nt.Package) string {
|
||||
num, err := strconv.Atoi(pack.Data)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
size := Chain.Size()
|
||||
if uint64(num) < size {
|
||||
return selectBlock(Chain, num)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getLastHash(pack *nt.Package) string {
|
||||
return bc.Base64Encode(Chain.LastHash())
|
||||
}
|
||||
|
||||
func getBalance(pack *nt.Package) string {
|
||||
return fmt.Sprintf("%d", Chain.Balance(pack.Data, Chain.Size()))
|
||||
}
|
||||
|
||||
func selectBlock(chain *bc.BlockChain, i int) string {
|
||||
var block string
|
||||
row := chain.DB.QueryRow("SELECT Block FROM BlockChain WHERE Id=$1", i+1)
|
||||
row.Scan(&block)
|
||||
return block
|
||||
}
|
||||
|
||||
func addTransaction(pack *nt.Package) string {
|
||||
var tx = bc.DeserializeTX(pack.Data)
|
||||
if tx == nil || len(Block.Transactions) == bc.TXS_LIMIT {
|
||||
return "fail"
|
||||
}
|
||||
Mutex.Lock()
|
||||
err := Block.AddTransaction(Chain, tx)
|
||||
Mutex.Unlock()
|
||||
if err != nil {
|
||||
return "fail"
|
||||
}
|
||||
if len(Block.Transactions) == bc.TXS_LIMIT {
|
||||
go func() {
|
||||
Mutex.Lock()
|
||||
block := *Block
|
||||
IsMining = true
|
||||
Mutex.Unlock()
|
||||
res := (&block).Accept(Chain, User, BreakMining)
|
||||
Mutex.Lock()
|
||||
IsMining = false
|
||||
if res == nil && bytes.Equal(block.PrevHash, Block.PrevHash) {
|
||||
Chain.AddBlock(&block)
|
||||
pushBlockToNet(&block)
|
||||
}
|
||||
Block = bc.NewBlock(User.Address(), Chain.LastHash())
|
||||
Mutex.Unlock()
|
||||
}()
|
||||
}
|
||||
return "ok"
|
||||
}
|
||||
|
||||
func pushBlockToNet(block *bc.Block) {
|
||||
var (
|
||||
sblock = bc.SerializeBlock(block)
|
||||
msg = Serve + SEPARATOR + fmt.Sprintf("%d", Chain.Size()) + SEPARATOR + sblock
|
||||
)
|
||||
for _, addr := range Addresses {
|
||||
go nt.Send(addr, &nt.Package{
|
||||
Option: ADD_BLOCK,
|
||||
Data: msg,
|
||||
})
|
||||
}
|
||||
}
|
||||
60
cmd/node/values.go
Normal file
60
cmd/node/values.go
Normal file
@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
bc "blockchain-from-scratch/blockchain"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var (
|
||||
Addresses []string
|
||||
User *bc.User
|
||||
)
|
||||
|
||||
const (
|
||||
SEPARATOR = "_SEPARATOR_"
|
||||
)
|
||||
|
||||
const (
|
||||
ADD_BLOCK = iota + 1
|
||||
ADD_TRNSX
|
||||
GET_BLOCK
|
||||
GET_LHASH
|
||||
GET_BLNCE
|
||||
GET_CSIZE
|
||||
)
|
||||
|
||||
func userNew(filename string) *bc.User {
|
||||
user := bc.NewUser()
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
err := writeFile(filename, user.Purse())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func userLoad(filename string) *bc.User {
|
||||
priv := readFile(filename)
|
||||
if priv == "" {
|
||||
return nil
|
||||
}
|
||||
user := bc.LoadUser(priv)
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
func writeFile(filename string, data string) error {
|
||||
return ioutil.WriteFile(filename, []byte(data), 0644)
|
||||
}
|
||||
|
||||
func readFile(filename string) string {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user