Skip to content

Commit

Permalink
Merge branch 'main' into refactor/relayer/observer
Browse files Browse the repository at this point in the history
  • Loading branch information
ermyas authored Feb 8, 2022
2 parents 248dd5e + 9c23dd2 commit da4d0ff
Show file tree
Hide file tree
Showing 22 changed files with 636 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<Root level="${sys:root.log.level}">
<AppenderRef ref="Console" />
</Root>
<Logger name="net.consensys.gpact.cbc" level="DEBUG"/>
<Logger name="net.consensys.gpact.functioncall" level="DEBUG">
</Logger>
</Loggers>
</Configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<Root level="${sys:root.log.level}">
<AppenderRef ref="Console" />
</Root>
<Logger name="net.consensys.gpact.cbc" level="DEBUG">
<Logger name="net.consensys.gpact.functioncall" level="DEBUG">
</Logger>
</Loggers>
</Configuration>
4 changes: 3 additions & 1 deletion examples/gpact/hotel-train/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ on the Hotel and Train blockchains).

Note in the Travel Agency contract that it authenticates the call to book a hotel room
and a train seat, and the Hotel contract authenticates the crosschain call from the
Travel Agency, ensuring it is in fact the Travel Agency contract that is doing the call.
Travel Agency, ensuring it is in fact the Travel Agency contract that is doing the call.

[Click on this link to see the sequence diagram of the Hotel - Train example](https://sequencediagram.org/index.html#initialData=C4S2BsFMAIHEAUCCBhAKtAEge2Jc0BaaVAJwEMQA7aAUQA8yBbABymgFcBnKgc1oDdIlYNETBcnYGVBZKALmgBlEC3AgAZiEgATAFAAjHMCwsyJUAGMQzMsM67dN8yCs3hPElnbNoAYjU8ABbAAJ544FgA7tAAVDGIzKwu0iCy0MhY2pBxjmaW1rYiCUkWKbIAdABWZPxkuc6uhUoAIgDSukJ6DvX5bsAeXj6+zFQA1rExpDV4ojxCFiHQAEIRFqMWgRSUOU69TQBEAEp4ZGEk0AD0ouKQklgk+9BknKLH4KeQJGISxiQ9LgV3J5vH4AsEPJAhBMALK3ThkHi8aAAGQ+JB2eQBfWg+2+t1+yh4lGOiMk5BI5U4WHAj2eojxdxIhOJkFJwHJlOp-0awhxyE8nE4Gy2ADVPhotEyQETOTSni8UAKhZsqGKSBLPszZR1KNpoNzAf1gUMwcB9OB2DA4gAxdiUCwyajIMjgfCos4YhqGvlK4VUDLCTzgWW0hX8rCCv2UAPs6nazoGvoDEH+aXgkiQRZxYpqUqOlFoz17Xn7KaCcCIOb2kIh+XEcjlyvzGtU8A6vQJxOFZNDCFZmLYXD4FZYNZRotYg5vNGXa4-e6h5bTs4M35doGDUFpo2Q6hxWGChFI92fCc8kS4m6M5kkkBksy1ulLVf3G+su-sh+t9cX8ORlWUGqGpSjKraLksf7KqK4qaJq0qUPGuo-j2W5BGaFpWjEtr2vmzqugWHoxD+PoRlB-qyLGwZgXWEG+gBMZBohei7JOG4pqafYTDmyT5ie6JESx544oOeCPi8IlUVygnevsyKjqMZDmpANCHMgABMAAM8AZpwkDANaIB0DoijeKwLbUuBclrIpUAqepWk6XpBlGdoJmJOA5ltgmnbSUmxp+JxcRTFQyyrOsAFnjJy6fLOL4PHWyDRV8V5rsh-mpmhEJQvucJHpQfB8ZF2KXvOIEsmyHLUXSyBxW+FVflJmJCfskFRkBsFlWJ6StQB7WSlq36dmlm4ZcE5qWhM2EOqkToum6hYCU1Mk9VsDFxlVLzICt5GButXI+UtfkjRxGb9txeYzQRp6LV6xWwDYDp2ZpSzqtocxdcFCHfr5BxWQpSlPQ5txOYZxmmR5XXIH9NnKapmnacD+mg654Oee26MOAAvJj0AI04MDqPc6R0Vs9a2PC01pNjDiUDgMBYII5znWUCHVLUAA0LStAoyiMOw7y4NAFgkyFn6UBT+YADrCFg0BZLgJCMFQBN2pT1BOEwemfJw5Q03T0AMzFzOOlUNRkJzihtAo-KQNIMClPhkBGRY7D5uykK61jOPbdQUzi2QavQNTxszabtQEAAfJb3O0M7rv23N0BO5ALtuxmkBe3ASBoDzUjmEHmO6NHkeKqRUZrZJ4AKJIeTQAAFBYJhKyIxhC4nyep5d7uQAAlHrguG0zPsV7Kcg0M3AhCMAud5A4xcR4gSVxQosB6dAfPgKAZnS9wRI6EngjCJnCAoKgPOsowU-14YWDjJ4JhPCIgR0+APcF0XbSR7RZf0RRjGttXC+U8HDf3-KtP+e1wBfx9n1OCoFqRyCyI3LIiBdTtRCDQQ+wBdCgLIoBGC-V4Kyi-rVeCt57wUgAdARmGgQioO0MgQIKdRioECDpZ+4Aui4PLhAyukcJKj2gDfUYhwsAmF0AI1sX9oYAzhkDXSSMXJuTMoIsWnB1CfGtJ4Rg0sywzCbNWaArcJL93pozZYw9eGj3HmASewhz48EvkfD+rQv5LxSvcFea8N5bw8tAXelB96QCwd0bGWdT4OKcSIOuwj-G2xEGkT8VA37U3nltEW0YrFUN0o44Buh0k-3AbtPhEcClgNVAQuBX0EFIMyJAeh6DMHALKXg2BnUpGlNIUSchn5KEIOoTBOhupGHMNYew6kXQWk8OKcQiOn1BHCMUPE3Q8yOlQ3kjDQGCMFHOTBu5TyCg1EaJIFokwuiGz6KrAsIxstPqmINuYqZv8ZkAJsSIJp9ilBAOcWk9xpUvEiB8dYPxASgkhOPtnM+0BRE4HfvPUu5TMkvP6ffbBugEV4JHh0jFbVKntJqSnOpDTBkfOwTi3qeKBrUhLl08qH5Kr9JoeoIZDCmFrDGbcDhXRyVFMorMvRFYrkHKEWI0YEl6F3N0LTAe5ieU7T5a8iepKFAwrRfCv5+JPFwG8fzXxiwd7wTBXk3QYST45yUPBOaSJUmfwjtw55Cr+kBKtflEBljkVQLtTAylRCAG1JQWgklIT7XQXVB1KlnrnweLKj0hlVcBlhpZSM9lbDOUTLdRkrF1K7UyNsnI7ZIMlGo0EZoSgLo7wwDrhkRgE8ibNDvKUEgepmCeH4HeGaLoODMG0HbTgfcTU4zNVC5kLq+A2tcaU91jr43OtdLwBwTzeX-2zYuipYbCHwKrv6+pgbE2kvyd69dVTZk1WjXVelDV41MqTWylhqbOBcoXVO5dnr1nWVkfZAtii9kqKoaW8tul67VtrecetQozDNtbe22QnbvA9okH3IAA)
201 changes: 201 additions & 0 deletions examples/gpact/hotel-train/contracts/src/Train.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* Copyright 2021 ConsenSys Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
pragma solidity >=0.8;

import "../../../../../contracts/contracts/src/application/lockablestorage/LockableStorage.sol";
import "../../../../../contracts/contracts/src/functioncall/interface/AtomicHiddenAuthParameters.sol";
import "../../../../../contracts/contracts/src/openzeppelin/token/ERC20/IERC20.sol";

contract Train is LockableStorage, AtomicHiddenAuthParameters {
// Seat rate.
// Map (seat number => seat rate)
// mapping (uint256 => uint256) private roomRate;
uint256 private constant SEAT_RATE_MAP = 0;

// Booked by.
// Map (seat number => map (date => who booked seat))
// Map (uint256 => map (uint256 => address)) bookedBy;
uint256 private constant SEAT_BOOKED_BY_2MAP = 1;

// Map (booking reference => seat number)
// mapping(uint256 => uint256) bookingRefToSeatNumber;
uint256 private constant BOOKING_REF_TO_SEAT_NUMBER = 2;

// Map (booking reference => date)
// mapping(uint256 => uint256) bookingRefToDate;
uint256 private constant BOOKING_REF_TO_DATE = 3;

// Number of seats.
// For this example, the number of seats can never be smaller. If
// the number of seats could be reduced, then the system would need
// to be carefully designed for locking.
uint256 numSeats;

// For this example, new agencies can be added to the approved
// list. However, old agencies can never be removed. Additionally,
// the spending address can't be changed. If this functionality
// was required, the system would need to be carefully designed
// for locking.
// Map (address of travel agency contract => spender address for the travel agency)
mapping(address => address) travelAgencySpender;
// Map (blockchain id => address of travel agency contract)
mapping(uint256 => address) approvedTravelAgencies;

address owner;
IERC20 erc20;

modifier onlyOwner() {
require(msg.sender == owner);
_;
}

constructor(address _erc20, address _cbc) LockableStorage(_cbc) {
owner = msg.sender;
erc20 = IERC20(_erc20);
}

function addApprovedTravelAgency(
uint256 _blockchainId,
address _travelAgencyContract,
address spendingAccount
) external onlyOwner {
approvedTravelAgencies[_blockchainId] = _travelAgencyContract;
travelAgencySpender[_travelAgencyContract] = spendingAccount;
}

function addSeats(uint256 _seatRate, uint256 _numberOfSeats)
external
onlyOwner
{
for (uint256 i = 0; i < _numberOfSeats; i++) {
setMapValue(SEAT_RATE_MAP, numSeats++, _seatRate);
}
}

function changeSeatRate(uint256 _seatNumber, uint256 _seatRate)
external
onlyOwner
{
setMapValue(SEAT_RATE_MAP, _seatNumber, _seatRate);
}

function bookSeat(
uint256 _date,
uint256 _uniqueId,
uint256 _maxAmountToPay
) external {
require(address(cbc) == msg.sender, "Must be crosschain call");

// Check that the calling contract was the travel agency linked to this one from
// the source blockchain.
// TODO check that the root blockchain is trusted
(
,
uint256 sourceBlockchainId,
address sourceContract
) = decodeAtomicAuthParams();
require(
sourceContract == approvedTravelAgencies[sourceBlockchainId],
"Sender is not an approved travel agency"
);

require(_date != 0, "Date can not be zero");
for (uint256 i = 0; i < numSeats; i++) {
uint256 rate = getMapValue(SEAT_RATE_MAP, i);
// If amount is OK and the room is available.
if (
!isDoubleMapValueLocked(SEAT_BOOKED_BY_2MAP, i, _date) &&
rate <= _maxAmountToPay &&
address(
uint160(getDoubleMapValue(SEAT_BOOKED_BY_2MAP, i, _date))
) ==
address(0)
) {
// Book seat
setDoubleMapValue(
SEAT_BOOKED_BY_2MAP,
i,
_date,
uint160(tx.origin)
);
setMapValue(BOOKING_REF_TO_SEAT_NUMBER, _uniqueId, i);
setMapValue(BOOKING_REF_TO_DATE, _uniqueId, _date);
// Pay for room.
erc20.transferFrom(
travelAgencySpender[sourceContract],
owner,
rate
);
return;
}
}
require(false, "No seats available");
}

function getBookingInformation(uint256 _uniqueId)
external
view
returns (
uint256 amountPaid,
uint256 seatId,
uint256 date
)
{
date = getMapValue(BOOKING_REF_TO_DATE, _uniqueId);
if (date == 0) {
amountPaid = 0;
seatId = 0;
} else {
seatId = getMapValue(BOOKING_REF_TO_SEAT_NUMBER, _uniqueId);
amountPaid = getMapValue(SEAT_RATE_MAP, seatId);
}
}

function getNumberSeatsAvailable(uint256 _date)
public
view
returns (uint256 numSeatsAvailable)
{
numSeatsAvailable = 0;
for (uint256 i = 0; i < numSeats; i++) {
if (
!isDoubleMapValueLocked(SEAT_BOOKED_BY_2MAP, i, _date) &&
getDoubleMapValue(SEAT_BOOKED_BY_2MAP, i, _date) == 0
) {
numSeatsAvailable++;
}
}
}

function getBookings(uint256 _date)
external
view
returns (address[] memory bookings)
{
uint256 numAvailable = getNumberSeatsAvailable(_date);
bookings = new address[](numSeats - numAvailable);
uint256 index = 0;
for (uint256 i = 0; i < numSeats; i++) {
if (!isDoubleMapValueLocked(SEAT_BOOKED_BY_2MAP, i, _date)) {
address bookedBy = address(
uint160(getDoubleMapValue(SEAT_BOOKED_BY_2MAP, i, _date))
);
if (bookedBy != address(0)) {
bookings[index++] = bookedBy;
}
}
}
}
}
7 changes: 4 additions & 3 deletions examples/gpact/hotel-train/contracts/src/TravelAgency.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
pragma solidity >=0.8;

import "./Hotel.sol";
import "./Train.sol";
import "../../../../../contracts/contracts/src/functioncall/interface/CrosschainFunctionCallInterface.sol";
import "../../../../../contracts/contracts/src/functioncall/interface/CrosschainFunctionCallReturnInterface.sol";

Expand All @@ -25,7 +26,7 @@ contract TravelAgency is LockableStorage {
Hotel public hotelContract;

uint256 public trainBlockchainId;
Hotel public trainContract;
Train public trainContract;

// Confirmed bookings.
// Map (bookingId => date)
Expand All @@ -43,7 +44,7 @@ contract TravelAgency is LockableStorage {
hotelBlockchainId = _hotelBlockchainId;
hotelContract = Hotel(_hotelContract);
trainBlockchainId = _trainBlockchainId;
trainContract = Hotel(_trainContract);
trainContract = Train(_trainContract);
}

function bookHotelAndTrain(uint256 _date, uint256 _bookingId) public {
Expand All @@ -67,7 +68,7 @@ contract TravelAgency is LockableStorage {
trainBlockchainId,
address(trainContract),
abi.encodeWithSelector(
trainContract.bookRoom.selector,
trainContract.bookSeat.selector,
_date,
_bookingId,
100
Expand Down
2 changes: 2 additions & 0 deletions examples/gpact/hotel-train/java/gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ WEB3J=../web3j-abi/codegen/build/install/codegen/bin/codegen

solc $CONTRACTSDIR/TravelAgency.sol --bin --abi --optimize -o $BUILDDIR --overwrite
solc $CONTRACTSDIR/Hotel.sol --bin --abi --optimize -o $BUILDDIR --overwrite
solc $CONTRACTSDIR/Train.sol --bin --abi --optimize -o $BUILDDIR --overwrite
# ls -al $BUILDDIR

$WEB3J solidity generate -r -a=$BUILDDIR/TravelAgency.abi -b=$BUILDDIR/TravelAgency.bin -o=$OUTPUTDIR -p=$PACKAGE
$WEB3J solidity generate -r -a=$BUILDDIR/Hotel.abi -b=$BUILDDIR/Hotel.bin -o=$OUTPUTDIR -p=$PACKAGE
$WEB3J solidity generate -r -a=$BUILDDIR/Train.abi -b=$BUILDDIR/Train.bin -o=$OUTPUTDIR -p=$PACKAGE

solc applications/gpact/erc20bridge/contracts/src/presets/LockableERC20PresetFixedSupply.sol --bin --abi --optimize -o $BUILDDIR --overwrite
$WEB3J solidity generate -r -a=$BUILDDIR/LockableERC20PresetFixedSupply.abi -b=$BUILDDIR/LockableERC20PresetFixedSupply.bin -o=$OUTPUTDIR -p=$PACKAGE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,21 @@

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import net.consensys.gpact.common.AbstractBlockchain;
import net.consensys.gpact.common.BlockchainId;
import net.consensys.gpact.common.DynamicGasProvider;
import net.consensys.gpact.soliditywrappers.examples.gpact.hoteltrain.Hotel;
import net.consensys.gpact.soliditywrappers.examples.gpact.hoteltrain.LockableERC20PresetFixedSupply;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.web3j.crypto.Credentials;
import org.web3j.tuples.generated.Tuple3;

public class EntityBase extends AbstractBlockchain {
private static final Logger LOG = LogManager.getLogger(EntityBase.class);

// Total number of tokens issued for booking.
public static final BigInteger TOKEN_SUPPLY = BigInteger.valueOf(1000);

LockableERC20PresetFixedSupply erc20;
Hotel hotelContract;
private LockableERC20PresetFixedSupply erc20;
public String entity;

public EntityBase(
Expand All @@ -49,7 +45,7 @@ public EntityBase(
this.entity = entity;
}

public void deployContracts(String cbcAddress) throws Exception {
protected String deployERC20Contract(String cbcAddress) throws Exception {
LOG.info(" Deploy ERC20 contract for {}", this.entity);
LOG.info(" Setting total supply as {} tokens", TOKEN_SUPPLY);
String name = "ABC";
Expand All @@ -67,15 +63,7 @@ public void deployContracts(String cbcAddress) throws Exception {
owner)
.send();

LOG.info(" Deploy {} contract", this.entity);
this.hotelContract =
Hotel.deploy(
this.web3j, this.tm, this.gasProvider, this.erc20.getContractAddress(), cbcAddress)
.send();
}

public String getHotelContractAddress() {
return this.hotelContract.getContractAddress();
return this.erc20.getContractAddress();
}

public String getErc20ContractAddress() {
Expand All @@ -91,15 +79,6 @@ public void buyTokens(final String account, final int number) throws Exception {
LOG.info(" New balance of account {}: {}", account, balance1);
}

public void addTravelAgency(
BlockchainId travelAgencyBcId, String travelAgencyContractAddress, String tokenHoldingAccount)
throws Exception {
this.hotelContract
.addApprovedTravelAgency(
travelAgencyBcId.asBigInt(), travelAgencyContractAddress, tokenHoldingAccount)
.send();
}

public void showErc20Balances(String[] accounts) throws Exception {
LOG.info(" {} ERC 20 Balances", this.entity);
BigInteger myBal = this.erc20.balanceOf(this.credentials.getAddress()).send();
Expand All @@ -115,29 +94,4 @@ public void showErc20Allowance(String owner, String spender) throws Exception {
BigInteger allowance = this.erc20.allowance(owner, spender).send();
LOG.info(" {}: Owner {}: Spender: {}: Allowance: {}", this.entity, owner, spender, allowance);
}

public void showBookingInformation(BigInteger bookingId) throws Exception {
Tuple3<BigInteger, BigInteger, BigInteger> retVal =
this.hotelContract.getBookingInformation(bookingId).send();
BigInteger amountPaid = retVal.component1();
BigInteger roomId = retVal.component2();
BigInteger date = retVal.component3();

LOG.info(
" {} Booking: Date: {}, Room/Seat: {}, Amount: {}", this.entity, date, roomId, amountPaid);
}

public void showBookings(int date) throws Exception {
LOG.info(" Hotel Bookings for date: {}", date);
List<String> hotelBookings = this.hotelContract.getBookings(BigInteger.valueOf(date)).send();
for (String booking : hotelBookings) {
LOG.info(" Room booked for {}", booking);
}

LOG.info(" Train Bookings for date: {}", date);
List<String> trainBookings = this.hotelContract.getBookings(BigInteger.valueOf(date)).send();
for (String booking : trainBookings) {
LOG.info(" Seat booked for {}", booking);
}
}
}
Loading

0 comments on commit da4d0ff

Please sign in to comment.