diff --git a/.gitignore b/.gitignore index d8e6ca6..4f8f9fd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,18 @@ mainbc mainnt node client +client_eth gclient +gclient_eth node1.key node2.key chain1.db chain2.db todo.txt blockchain.db +contract.address +deploy +contracts/Contract.go +build/WorldSkills.abi +build/WorldSkills.bin +abigen diff --git a/Makefile b/Makefile index fbd5160..cc0e72f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,15 @@ -.PHONY: default build -default: build -build: node.go client.go gclient.go serve.go values.go +.PHONY: default xbuild ybuild +default: xbuild ybuild +# Self-written part +xbuild: node.go client.go gclient.go serve.go values.go go build -o node node.go serve.go values.go go build -o client client.go values.go go build -o gclient gclient.go values.go +# Ethereum part +ybuild: contract.sol deploy.go client_eth.go gclient_eth.go values_eth.go + solc --overwrite --abi --bin contract.sol -o build + mkdir -p contracts + ./abigen --bin=./build/WorldSkills.bin --abi=./build/WorldSkills.abi --pkg=contract --out=./contracts/Contract.go + go build -o deploy deploy.go + go build -o client_eth client_eth.go values_eth.go + go build -o gclient_eth gclient_eth.go values_eth.go diff --git a/client_eth.go b/client_eth.go new file mode 100644 index 0000000..9c58b9e --- /dev/null +++ b/client_eth.go @@ -0,0 +1,720 @@ +package main + +import ( + "os" + "fmt" + "bufio" + "context" + "strings" + "math/big" + "encoding/json" + "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": + switch splited[2] { + case "estates": + // chain get estates address + chainGetEstates(splited[2:]) + case "presents": + // chain get presents address + chainGetPresents(splited[2:]) + case "sales": + // chain get sales address + chainGetSales(splited[2:]) + case "rents": + // chain get rents address + chainGetRents(splited[2:]) + default: + fmt.Println("command undefined\n") + } + 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": + switch splited[2] { + case "present": + // chain cancel present id_present + chainCancelPresent(splited[2:]) + case "sale": + // chain cancel sale id_sale + chainCancelSale(splited[2:]) + case "rent": + // chain cancel rent id_rent + chainCancelRent(splited[2:]) + default: + fmt.Println("command undefined\n") + } + 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 chainCancelPresent(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.CancelPresent( + resetAuth(User), + presentNumber, + ) + if err != nil { + fmt.Println(err, "\n") + return + } + fmt.Println("Tx:", tx.Hash().Hex(), "\n") +} + +func chainCancelSale(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.CancelSale( + resetAuth(User), + saleNumber, + ) + if err != nil { + fmt.Println(err, "\n") + return + } + fmt.Println("Tx:", tx.Hash().Hex(), "\n") +} + +func chainCancelRent(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.CancelRent( + resetAuth(User), + rentNumber, + ) + 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 chainGetEstates(splited []string) { + if len(splited) != 2 { + fmt.Println("failed: len(splited) != 2\n") + return + } + var inc = big.NewInt(1) + estatesnum, err := Instance.GetEstatesNumber(&bind.CallOpts{From: User.AddressEth}) + if err != nil { + fmt.Println(err, "\n") + return + } + for index := big.NewInt(0) ; index.Cmp(estatesnum) == -1; index.Add(index, inc) { + 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") + if err != nil { + fmt.Println(err, "\n") + return + } + fmt.Println(string(jsonData)) + } + fmt.Println() +} + +func chainGetPresents(splited []string) { + if len(splited) != 2 { + fmt.Println("failed: len(splited) != 2\n") + return + } + var inc = big.NewInt(1) + prenetsnum, err := Instance.GetPresentsNumber(&bind.CallOpts{From: User.AddressEth}) + if err != nil { + fmt.Println(err, "\n") + return + } + for index := big.NewInt(0); index.Cmp(prenetsnum) == -1; index.Add(index, inc) { + 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") + if err != nil { + fmt.Println(err, "\n") + return + } + fmt.Println(string(jsonData)) + } + fmt.Println() +} + +func chainGetSales(splited []string) { + if len(splited) != 2 { + fmt.Println("failed: len(splited) != 2\n") + return + } + var inc = big.NewInt(1) + salesnum, err := Instance.GetSalesNumber(&bind.CallOpts{From: User.AddressEth}) + if err != nil { + fmt.Println(err, "\n") + return + } + for index := big.NewInt(0); index.Cmp(salesnum) == -1; index.Add(index, inc) { + 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") + if err != nil { + fmt.Println(err, "\n") + return + } + fmt.Println(string(jsonData)) + } + fmt.Println() +} + +func chainGetRents(splited []string) { + if len(splited) != 2 { + fmt.Println("failed: len(splited) != 2\n") + return + } + var inc = big.NewInt(1) + rentsnum, err := Instance.GetRentsNumber(&bind.CallOpts{From: User.AddressEth}) + if err != nil { + fmt.Println(err, "\n") + return + } + for index := big.NewInt(0); index.Cmp(rentsnum) == -1; index.Add(index, inc) { + 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") + 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) +} diff --git a/contract.sol b/contract.sol new file mode 100644 index 0000000..d415371 --- /dev/null +++ b/contract.sol @@ -0,0 +1,256 @@ +pragma solidity ^0.5.0; + + +contract WorldSkills { + + struct Estate { + uint estate_id; + address owner; + string info; + uint squere; + uint useful_squere; + address renter_address; + bool present_status; + bool sale_status; + bool rent_status; + } + + struct Present { + uint estate_id; + address address_from; + address address_to; + bool finished; + } + + struct Sale { + uint estate_id; + address owner; + uint price; + address payable[] customers; + uint[] prices; + bool finished; + } + + struct Rent { + uint estate_id; + address payable owner_address; + address payable renter_address; + uint time; + uint money; + uint deadline; + bool finished; + } + + Estate[] estates; + Present[] presents; + Sale[] sales; + Rent[] rents; + + address admin = msg.sender; + address payable default_address = 0x0000000000000000000000000000000000000000; + + // ADD FUNCTION + function iam_admin() public view returns(bool) { + return msg.sender == admin; + } + + function get_estates_number() public view returns(uint) { + return estates.length; + } + + function get_presents_number() public view returns(uint) { + return presents.length; + } + + function get_sales_number() public view returns(uint) { + return sales.length; + } + + function get_rents_number() public view returns(uint) { + return rents.length; + } + + + + + function get_estates(uint estate_number) public view returns(uint, address, string memory, uint, uint, address) { + return(estates[estate_number].estate_id, estates[estate_number].owner, estates[estate_number].info, estates[estate_number].squere, estates[estate_number].useful_squere, estates[estate_number].renter_address); + } + + function get_estates_statuses(uint estate_number) public view returns(bool, bool, bool) { + return(estates[estate_number].present_status, estates[estate_number].sale_status, estates[estate_number].rent_status); + } + + function get_presents(uint present_number) public view returns(uint, address, address, bool) { + return(presents[present_number].estate_id, presents[present_number].address_from, presents[present_number].address_to, presents[present_number].finished); + } + + function get_sales(uint sale_number) public view returns(uint, address, uint, address payable[] memory, uint[] memory prices, bool) { + return(sales[sale_number].estate_id, sales[sale_number].owner, sales[sale_number].price, sales[sale_number].customers, sales[sale_number].prices, sales[sale_number].finished); + } + + function get_rents(uint rent_number) public view returns(uint, address, address, uint, uint, uint, bool) { + return(rents[rent_number].estate_id, rents[rent_number].owner_address, rents[rent_number].renter_address, rents[rent_number].time, rents[rent_number].money, rents[rent_number].deadline, rents[rent_number].finished); + } + + modifier status_OK(uint estate_id) { + require(estates[estate_id].present_status == false); + require(estates[estate_id].sale_status == false); + require(estates[estate_id].rent_status == false); + _; + } + + modifier is_owner(uint estate_id) { + require(msg.sender == estates[estate_id].owner); + _; + } + + modifier is_admin { + require(msg.sender == admin); + _; + } + + //Admin's function + // РАБОТАЕТ + //Создать объект собственности + function create_estate(address owner, string memory info, uint squere, uint useful_squere) public is_admin{ + estates.push(Estate(estates.length, owner, info, squere, useful_squere, 0x0000000000000000000000000000000000000000, false, false, false)); + } + + //Present's functions + + // Создать предложение подарка + function create_present(uint estate_id, address address_to) public status_OK(estate_id) is_owner(estate_id) { + presents.push(Present(estate_id, msg.sender, address_to, false)); + estates[estate_id].present_status = true; + } + + // Отменить свой подарок(доступна до принятие подарка адресатом) + function cancel_present(uint present_number) payable public { + require(msg.sender == presents[present_number].address_from); + require(presents[present_number].finished == false); + estates[presents[present_number].estate_id].present_status = false; + presents[present_number].finished = true; + + } + + // Принять подарок + function confirm_present(uint present_number) payable public { + require(msg.sender == presents[present_number].address_to); + require(presents[present_number].finished == false); + estates[presents[present_number].estate_id].owner = presents[present_number].address_to; + estates[presents[present_number].estate_id].present_status = false; + presents[present_number].finished = true; + + } + + + //Sale's functions + + // Разместить объявление о продаже + function create_sale(uint estate_id, uint price) public status_OK(estate_id) is_owner(estate_id){ + address payable[] memory customers; + uint[] memory prices; + sales.push(Sale(estate_id, msg.sender, price, customers, prices, false)); + estates[estate_id].sale_status = true; + } + + // Отменить объявление о продаже и вернуть деньги всем, кто успел внести + function cancel_sale(uint sale_number) public { + require(msg.sender == sales[sale_number].owner); + require(sales[sale_number].finished == false); + for (uint i = 0; i < sales[sale_number].customers.length; i++){ + (sales[sale_number].customers[i]).transfer(sales[sale_number].prices[i]); + } + estates[sales[sale_number].estate_id].sale_status = false; + sales[sale_number].finished = true; + + } + + // Выбрать чтобы купить + function check_to_buy(uint sale_number) public payable { + require(msg.sender != sales[sale_number].owner); + require(msg.value >= sales[sale_number].price); + require(sales[sale_number].finished == false); + uint status = 0; + for (uint i=0; i < sales[sale_number].customers.length; i++) { + if (sales[sale_number].customers[i] == msg.sender) { + status = 1; + break; + } + } + require(status == 0); + sales[sale_number].customers.push(msg.sender); + sales[sale_number].prices.push(msg.value); + } + + // Отменить выбор покупки + function cancel_to_buy(uint sale_number) public payable { + require(sales[sale_number].finished == false); + for (uint i=0; i +
+
+
+ +
+
+ +
+
+
+ +{{end}} diff --git a/templates_eth/base.html b/templates_eth/base.html new file mode 100644 index 0000000..71e6f44 --- /dev/null +++ b/templates_eth/base.html @@ -0,0 +1,43 @@ + + + + + {{block "title" .}} + Title + {{end}} + + + + + +
+ +
+
+
+ {{block "content" .}} + Content + {{end}} +
+
+ + diff --git a/templates_eth/blockchain.html b/templates_eth/blockchain.html new file mode 100644 index 0000000..302f0ea --- /dev/null +++ b/templates_eth/blockchain.html @@ -0,0 +1,45 @@ +{{define "title"}} + Chain +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ end }} + + {{ if .IsAdmin }} +
+
+
+
+ +
+
+ +
+
+ +
+ +
+
+
+ {{ end }} + +
+
+ Estates +
+
+ Presents +
+
+ Sales +
+
+ Rents +
+
+{{end}} diff --git a/templates_eth/estates.html b/templates_eth/estates.html new file mode 100644 index 0000000..332235b --- /dev/null +++ b/templates_eth/estates.html @@ -0,0 +1,32 @@ +{{define "title"}} + Estates +{{end}} + +{{define "content"}} +
+
+
+
+ {{ if .Address }} + + {{ end }} +
+
+ +
+ +
+
+
+
+ {{ if .Error }} + {{ .Error }} + {{ else }} + {{ range $i, $e := .Blocks }} + + {{ end }} + {{ end }} +
+{{end}} diff --git a/templates_eth/estatesX.html b/templates_eth/estatesX.html new file mode 100644 index 0000000..11808db --- /dev/null +++ b/templates_eth/estatesX.html @@ -0,0 +1,63 @@ +{{define "title"}} + Estate +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (and (eq .Block.Owner .User.AddressHex) (not .Block.PresentStatus) (not .Block.SaleStatus) (not .Block.RentStatus)) }} +
+ +
+ Do sales +
+
+ Do rents +
+
+ {{ end }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
Owner{{ .Block.Owner }}
Info{{ .Block.Info }}
Squere{{ .Block.Squere }}
UsefulSquere{{ .Block.UsefulSquere }}
RenterAddress{{ .Block.RenterAddress }}
PresentStatus{{ .Block.PresentStatus }}
SaleStatus{{ .Block.SaleStatus }}
RentStatus{{ .Block.RentStatus }}
+ {{ end }} +{{end}} diff --git a/templates_eth/index.html b/templates_eth/index.html new file mode 100644 index 0000000..884e07d --- /dev/null +++ b/templates_eth/index.html @@ -0,0 +1,9 @@ +{{define "title"}} + Index +{{end}} + +{{define "content"}} +
+

Blockchain

+
+{{end}} diff --git a/templates_eth/login.html b/templates_eth/login.html new file mode 100644 index 0000000..0a2179b --- /dev/null +++ b/templates_eth/login.html @@ -0,0 +1,22 @@ +{{define "title"}} + Login +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} +
+
+
+
+ +
+ +
+
+
+ {{ end }} +{{end}} diff --git a/templates_eth/presents.html b/templates_eth/presents.html new file mode 100644 index 0000000..30df907 --- /dev/null +++ b/templates_eth/presents.html @@ -0,0 +1,32 @@ +{{define "title"}} + Presents +{{end}} + +{{define "content"}} +
+
+
+
+ {{ if .Address }} + + {{ end }} +
+
+ +
+ +
+
+
+
+ {{ if .Error }} +

{{ .Error }}

+ {{ else }} + {{ range $i, $e := .Blocks }} + + {{ end }} + {{ end }} +
+{{end}} diff --git a/templates_eth/presentsDo.html b/templates_eth/presentsDo.html new file mode 100644 index 0000000..55b2a28 --- /dev/null +++ b/templates_eth/presentsDo.html @@ -0,0 +1,62 @@ +{{define "title"}} + Present +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (eq .Block.Owner .User.AddressHex )}} +
+
+
+
+ +
+ +
+
+
+ {{ end }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
Owner{{ .Block.Owner }}
Info{{ .Block.Info }}
Squere{{ .Block.Squere }}
UsefulSquere{{ .Block.UsefulSquere }}
RenterAddress{{ .Block.RenterAddress }}
PresentStatus{{ .Block.PresentStatus }}
SaleStatus{{ .Block.SaleStatus }}
RentStatus{{ .Block.RentStatus }}
+ {{ end }} +{{end}} diff --git a/templates_eth/presentsX.html b/templates_eth/presentsX.html new file mode 100644 index 0000000..fabd9be --- /dev/null +++ b/templates_eth/presentsX.html @@ -0,0 +1,52 @@ +{{define "title"}} + Present +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (eq .Block.AddressFrom .User.AddressHex )}} +
+
+
+ +
+
+
+ {{ end }} + {{ if (eq .Block.AddressTo .User.AddressHex )}} +
+
+
+ +
+
+
+ {{ end }} + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
EstateId{{ .Block.EstateId }}
AddressFrom{{ .Block.AddressFrom }}
AddressTo{{ .Block.AddressTo }}
Finished{{ .Block.Finished }}
+ {{ end }} +{{end}} diff --git a/templates_eth/rents.html b/templates_eth/rents.html new file mode 100644 index 0000000..707583e --- /dev/null +++ b/templates_eth/rents.html @@ -0,0 +1,32 @@ +{{define "title"}} + Rents +{{end}} + +{{define "content"}} +
+
+
+
+ {{ if .Address }} + + {{ end }} +
+
+ +
+ +
+
+
+
+ {{ if .Error }} + Error: {{ .Error }} + {{ else }} + {{ range $i, $e := .Blocks }} + + {{ end }} + {{ end }} +
+{{end}} diff --git a/templates_eth/rentsDo.html b/templates_eth/rentsDo.html new file mode 100644 index 0000000..13478c4 --- /dev/null +++ b/templates_eth/rentsDo.html @@ -0,0 +1,65 @@ +{{define "title"}} + Rent +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (eq .Block.Owner .User.AddressHex )}} +
+
+
+
+ +
+
+ +
+ +
+
+
+ {{ end }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
Owner{{ .Block.Owner }}
Info{{ .Block.Info }}
Squere{{ .Block.Squere }}
UsefulSquere{{ .Block.UsefulSquere }}
RenterAddress{{ .Block.RenterAddress }}
PresentStatus{{ .Block.PresentStatus }}
SaleStatus{{ .Block.SaleStatus }}
RentStatus{{ .Block.RentStatus }}
+ {{ end }} +{{end}} diff --git a/templates_eth/rentsX.html b/templates_eth/rentsX.html new file mode 100644 index 0000000..b25595f --- /dev/null +++ b/templates_eth/rentsX.html @@ -0,0 +1,75 @@ +{{define "title"}} + Rent +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (eq .Block.Owner .User.AddressHex)}} + {{ if (not .Confirmed) }} +
+
+
+ +
+
+
+ {{ else }} +
+
+
+ +
+
+
+ {{ end}} + {{ else }} + {{ if (eq .Block.Renter "0x0000000000000000000000000000000000000000")}} +
+
+
+ +
+
+
+ {{ end }} + {{ end }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
EstateId{{ .Block.EstateId }}
Owner{{ .Block.Owner }}
Renter{{ .Block.Renter }}
Time{{ .Block.Time }}
Money{{ .Block.Money }}
DeadLine{{ .Block.DeadLine }}
Finished{{ .Block.Finished }}
+ {{ end }} +{{end}} diff --git a/templates_eth/sales.html b/templates_eth/sales.html new file mode 100644 index 0000000..bf75e9d --- /dev/null +++ b/templates_eth/sales.html @@ -0,0 +1,32 @@ +{{define "title"}} + Sales +{{end}} + +{{define "content"}} +
+
+
+
+ {{ if .Address }} + + {{ end }} +
+
+ +
+ +
+
+
+
+ {{ if .Error }} +

{{ .Error }}

+ {{ else }} + {{ range $i, $e := .Blocks }} + + {{ end }} + {{ end }} +
+{{end}} diff --git a/templates_eth/salesDo.html b/templates_eth/salesDo.html new file mode 100644 index 0000000..0b12fb2 --- /dev/null +++ b/templates_eth/salesDo.html @@ -0,0 +1,62 @@ +{{define "title"}} + Sale +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (eq .Block.Owner .User.AddressHex )}} +
+
+
+
+ +
+ +
+
+
+ {{ end }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
Owner{{ .Block.Owner }}
Info{{ .Block.Info }}
Squere{{ .Block.Squere }}
UsefulSquere{{ .Block.UsefulSquere }}
RenterAddress{{ .Block.RenterAddress }}
PresentStatus{{ .Block.PresentStatus }}
SaleStatus{{ .Block.SaleStatus }}
RentStatus{{ .Block.RentStatus }}
+ {{ end }} +{{end}} diff --git a/templates_eth/salesX.html b/templates_eth/salesX.html new file mode 100644 index 0000000..4e46011 --- /dev/null +++ b/templates_eth/salesX.html @@ -0,0 +1,95 @@ +{{define "title"}} + Sale +{{end}} + +{{define "content"}} + {{ if .Error }} +
+

{{ .Error }}

+
+ {{ else }} + {{ if (eq .Block.Owner .User.AddressHex )}} +
+
+
+ +
+
+
+
+
+ {{ else }} + {{ if .InCustomers}} +
+
+
+ +
+
+
+ {{ else }} +
+
+
+
+ +
+ +
+
+
+ {{ end }} + {{ end }} + + + + + + + + + + + + + + + + + + + + + + + + + +
Id{{ .Block.Id }}
EstateId{{ .Block.EstateId }}
Owner{{ .Block.Owner }} - {{ .User.AddressHex }}
Price{{ .Block.Price }}
Customers + {{ $owner := .Block.Owner }} + {{ $useraddr := .User.AddressHex }} + {{ $prices := .Block.Prices }} + {{ range $i, $e := .Block.Customers }} + + + + + + + + + + {{ if (eq $owner $useraddr) }} + + + + + {{ end }} +
Customer{{ $e }}
Price{{ index $prices $i }}
Confirm + + +
+ {{ end }} +
Finished{{ .Block.Finished }}
+ {{ end }} +{{end}} diff --git a/values_eth.go b/values_eth.go new file mode 100644 index 0000000..42f3fa1 --- /dev/null +++ b/values_eth.go @@ -0,0 +1,301 @@ +package main + +import ( + "context" + "math/big" + "io/ioutil" + "crypto/ecdsa" + contract "./contracts" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/accounts/abi/bind" +) + +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") + ContractAddr = common.HexToAddress(readFile("contract.address")) + Instance = newContract(ContractAddr, 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, + } +}