Hyperledger Burrow初体验

环境

os:ubuntu18.04
burrow:v0.30.2
solc:0.6.3-develop
go:1.14

下载、编译Burrow

git clone https://github.com/hyperledger/burrow.git
cd burrow
git checkout v0.30.2
make build
cp bin/burrow .

需要修改下Makefile才能编译通过,部分代码样式有问题 check不能通过
build: check build_burrow 修改成 build: build_burrow

burrow子命令

❯ ./burrow --help

Usage: burrow [--version] [--directory=<working directory>] COMMAND [arg...]

The EVM smart contract machine with Tendermint consensus

Options:
  -v, --version     Print the Burrow version
  -C, --directory   Change directory before running

Commands:
  start             Start a Burrow node
  spec              Build a GenesisSpec that acts as a template for a GenesisDoc and the configure command
  configure         Create Burrow configuration by consuming a GenesisDoc or GenesisSpec, creating keys, and emitting the config
  keys              A tool for doing a bunch of cool stuff with keys
  explore           Dump objects from an offline Burrow .burrow directory
  deploy            Deploy and test contracts
  natives           Dump Solidity interface contracts for Burrow native contracts
  vent              Start the Vent EVM event and blocks consumer service to populated databases from smart contracts
  dump              Dump chain state to backup
  tx                Submit a transaction to a burrow node
  restore           Restore new chain from backup
  accounts          List accounts and metadata
  abi               List, decode and encode using ABI

生成配置

./burrow spec -p1 -f1 | ./burrow configure -s- > burrow.toml

相当于

./burrow spec --participant-accounts=1 --full-accounts=1 > genesis-spec.json
./burrow configure --genesis-spec=genesis-spec.json > burrow.toml

–participant-accounts=1=>p1
–full-accounts=1=>f1

burrow.toml

BurrowDir = ".burrow"

[GenesisDoc]
  GenesisTime = 2020-04-01T01:43:22Z
  ChainName = "BurrowChain_FAB3C1"
  [GenesisDoc.Params]
    ProposalThreshold = 3
  [GenesisDoc.GlobalPermissions]
    [GenesisDoc.GlobalPermissions.Base]
      Perms = "send | call | createContract | createAccount | bond | name | proposal | input | batch | hasBase | hasRole"
      SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Accounts]]
    Address = "36B2954A8683E779B0B719E24327FD0B0ADCB004"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"A0BBD9E544023C67C4B02F9A41A3F4F36490848221F5508C7D3B4187A81AF37A\"}"
    Amount = 99999999999999
    Name = "Full_0"
    [GenesisDoc.Accounts.Permissions]
      [GenesisDoc.Accounts.Permissions.Base]
        Perms = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"
        SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Accounts]]
    Address = "3123B63BF27A838CE693CADE22485049C2CCD6AA"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"957B6147025782295EEB3DE1935089C54B2A0A04DDABBD69049BF678ED5BA784\"}"
    Amount = 9999999999
    Name = "Participant_0"
    [GenesisDoc.Accounts.Permissions]
      [GenesisDoc.Accounts.Permissions.Base]
        Perms = "send | call | name | proposal | input | hasRole"
        SetBit = "send | call | name | proposal | input | hasRole"

  [[GenesisDoc.Validators]]
    Address = "36B2954A8683E779B0B719E24327FD0B0ADCB004"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"A0BBD9E544023C67C4B02F9A41A3F4F36490848221F5508C7D3B4187A81AF37A\"}"
    Amount = 9999999999
    Name = "Full_0"

    [[GenesisDoc.Validators.UnbondTo]]
      Address = "36B2954A8683E779B0B719E24327FD0B0ADCB004"
      PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"A0BBD9E544023C67C4B02F9A41A3F4F36490848221F5508C7D3B4187A81AF37A\"}"
      Amount = 9999999999

[Tendermint]
  Enabled = true
  Seeds = ""
  SeedMode = false
  PersistentPeers = ""
  ListenHost = "0.0.0.0"
  ListenPort = "26656"
  ExternalAddress = ""
  AddrBookStrict = false
  Moniker = ""
  IdentifyPeers = false
  AuthorizedPeers = ""
  CreateEmptyBlocks = "5m"

[Execution]
  TimeoutFactor = 0.33
  CallStackMaxDepth = 0
  DataStackInitialCapacity = 1024
  DataStackMaxDepth = 0

[Keys]
  GRPCServiceEnabled = true
  AllowBadFilePermissions = false
  RemoteAddress = ""
  KeysDirectory = ".keys"

[RPC]
  [RPC.Info]
    Enabled = true
    ListenHost = "0.0.0.0"
    ListenPort = "26658"
  [RPC.Profiler]
    Enabled = false
    ListenHost = "0.0.0.0"
    ListenPort = "6060"
  [RPC.GRPC]
    Enabled = true
    ListenHost = "0.0.0.0"
    ListenPort = "10997"
  [RPC.Metrics]
    Enabled = false
    ListenHost = "0.0.0.0"
    ListenPort = "9102"
    MetricsPath = "/metrics"
    BlockSampleSize = 100
  [RPC.Web3]
    Enabled = true
    ListenHost = "0.0.0.0"
    ListenPort = "26660"

[Logging]
  Trace = false
  NonBlocking = false
  [Logging.RootSink]
    [Logging.RootSink.Output]
      OutputType = "stdout"
      Format = "json"

启动Burrow

需要制定验证者,可以是序号(burrow.toml配置文件的validator),也可以是验证者address

nohup ./burrow start --validator=0  >burrow.log 2>&1 &

数据目录

❯ tree .burrow/
.burrow/
├── burrow_state.db
│   ├── 000001.log
│   ├── CURRENT
│   ├── LOCK
│   ├── LOG
│   └── MANIFEST-000000
├── config
│   ├── addrbook.json
│   └── node_key.json
└── data
    ├── blockstore.db
    │   ├── 000001.log
    │   ├── CURRENT
    │   ├── LOCK
    │   ├── LOG
    │   └── MANIFEST-000000
    ├── cs.wal
    │   └── wal
    ├── evidence.db
    │   ├── 000001.log
    │   ├── CURRENT
    │   ├── LOCK
    │   ├── LOG
    │   └── MANIFEST-000000
    └── state.db
        ├── 000001.log
        ├── CURRENT
        ├── LOCK
        ├── LOG
        └── MANIFEST-000000

交易

SENDER=36B2954A8683E779B0B719E24327FD0B0ADCB004
RECIPIENT=3123B63BF27A838CE693CADE22485049C2CCD6AA
AMOUNT=10
./burrow tx formulate send -s $SENDER -t $RECIPIENT -a $AMOUNT > tx.json

生成的配置tx.json

{
  "SendTx": {
    "Inputs": [
      {
        "Address": "36B2954A8683E779B0B719E24327FD0B0ADCB004",
        "Amount": 10
      }
    ],
    "Outputs": [
      {
        "Address": "3123B63BF27A838CE693CADE22485049C2CCD6AA",
        "Amount": 10
      }
    ]
  }
}

提交交易,会返回交易的hash

./burrow tx commit --file tx.json
B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7

再看看日志,有记录这笔交易

{"caller":"execution.go:228","component":"Executor","height":1,"log_channel":"Info","message":"Executing transaction","run_call":false,"run_id":"b93fc996-73bc-11ea-891b-c683e38da786","scope":"executor.Execute(tx txs.Tx)","time":"2020-04-01T02:02:51.254874625Z","tx":"TxEnvelope{Signatures: 1, Tx: Tx{ChainID: BurrowChain_FAB3C1-CC46B1; TxHash: B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7; Payload: {\"ChainID\":\"BurrowChain_FAB3C1-CC46B1\",\"Type\":\"SendTx\",\"Payload\":{\"Inputs\":[{\"Address\":\"36B2954A8683E779B0B719E24327FD0B0ADCB004\",\"Amount\":10,\"Sequence\":1}],\"Outputs\":[{\"Address\":\"3123B63BF27A838CE693CADE22485049C2CCD6AA\",\"Amount\":10}]}}}}","tx_hash":"B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7"}
{"ExecuteTx":"tx_hash:B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7","caller":"app.go:195","component":"ABCI_App","height":1,"log_channel":"Info","message":"Execution success","node_info":"Burrow_0.30.2_BurrowChain_FAB3C1-CC46B1_ValidatorID:36B2954A8683E779B0B719E24327FD0B0ADCB004","run_id":"b93fc996-73bc-11ea-891b-c683e38da786","scope":"abci.NewApp","time":"2020-04-01T02:02:51.255223345Z"}
{"caller":"execution.go:228","component":"Executor","height":2,"log_channel":"Info","message":"Executing transaction","run_call":true,"run_id":"b93fc996-73bc-11ea-891b-c683e38da786","scope":"executor.Execute(tx txs.Tx)","time":"2020-04-01T02:02:51.267540673Z","tx":"TxEnvelope{Signatures: 1, Tx: Tx{ChainID: BurrowChain_FAB3C1-CC46B1; TxHash: B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7; Payload: {\"ChainID\":\"BurrowChain_FAB3C1-CC46B1\",\"Type\":\"SendTx\",\"Payload\":{\"Inputs\":[{\"Address\":\"36B2954A8683E779B0B719E24327FD0B0ADCB004\",\"Amount\":10,\"Sequence\":1}],\"Outputs\":[{\"Address\":\"3123B63BF27A838CE693CADE22485049C2CCD6AA\",\"Amount\":10}]}}}}","tx_hash":"B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7"}
{"ExecuteTx":"tx_hash:B19F0824DECBDD2FEE43CB31438FA744A54F4EDEB81A1C856666EF44046C6AC7","caller":"app.go:218","component":"ABCI_App","height":1,"log_channel":"Info","message":"Execution success","node_info":"Burrow_0.30.2_BurrowChain_FAB3C1-CC46B1_ValidatorID:36B2954A8683E779B0B719E24327FD0B0ADCB004","run_id":"b93fc996-73bc-11ea-891b-c683e38da786","scope":"abci.NewApp","time":"2020-04-01T02:02:51.267838691Z"}

智能合约

这里要测试的合约可以在这里找到:https://github.com/hyperledger/burrow/tree/v0.30.2/tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked

合约主要是定义了一下几个变量:

  bool storedBool;
  bool storedBool2;
  int storedInt;
  uint storedUint;
  address storedAddress;
  bytes32 storedBytes;
  string storedString;

执行一组job,相对应的是调用这些变量的set、get方法。

先看看deploy怎么用的。

❯ ./burrow deploy --help

Usage: burrow deploy [--chain=<host:port>] [--keys=<host:port>] [--mempool-signing] [--dir=<root directory>] [--output=<output file>] [--wasm] [--set=<KEY=VALUE>]... [--bin-path=<path>] [--gas=<gas>] [--jobs=<concurrent playbooks>] [--address=<address>] [--fee=<fee>] [--amount=<amount>] [--local-abi] [--verbose] [--debug] [--timeout=<timeout>] [--list-proposals=<state> | --proposal-create| --proposal-verify | --proposal-vote] [FILE...]

Deploy and test contracts

Arguments:
  FILE                    path to playbook file which deploy should run. if also using the --dir flag, give the relative path to playbooks file, which should be in the same directory

Options:
  -c, --chain             chain to be used in IP:PORT format (default "127.0.0.1:10997")
  -s, --keys              IP:PORT of Burrow GRPC service which jobs should or otherwise transaction submitted unsigned for mempool signing in Burrow
  -p, --mempool-signing   Use Burrow's own keys connection to sign transactions - means that Burrow instance must have access to input account keys. Sequence numbers are set as transactions enter the mempool so concurrent transactions can be sent from same inputs.
  -i, --dir               root directory of app (will use pwd by default)
  -o, --output            filename for playbook output file. by default, this name will reflect the playbook passed (default "deploy.output.json")
  -e, --set               default sets to use; operates the same way as the [set] jobs, only before the jobs file is ran (and after default address
  -b, --bin-path          path to the bin directory jobs should use when saving binaries after the compile process defaults to --dir + /bin (default "[dir]/bin")
  -g, --gas               default gas to use; can be overridden for any single job (default "1111111111")
  -j, --jobs              default number of concurrent playbooks to run if multiple are specified (default 1)
  -a, --address           default address (or account name) to use; operates the same way as the [account] job, only before the deploy file is ran
  -n, --fee               default fee to use (default "9999")
  -m, --amount            default amount to use (default "9999")
  -v, --verbose           verbose output
      --local-abi         use local ABIs rather than fetching them from burrow
      --wasm              Compile to WASM using solang (experimental)
  -d, --debug             debug level output
      --proposal-verify   Verify any proposal, do NOT create new proposal or vote
      --proposal-vote     Vote for proposal, do NOT create new proposal
      --proposal-create   Create new proposal
  -t, --timeout           Timeout to talk to the chain in seconds (default 15)
      --list-proposals    List proposals, either all, executed, expired, or current

ADDRESS 替换成toml文件中GenesisDoc.Accounts中的ADDRESS,然后指定deploy.yaml

ADDRESS=7CEDE838329CDE8C8302AC31EEBAF0EEA4BE61E5
./burrow deploy --address $ADDRESS  tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked/deploy.yaml

执行后,报错了,缺少solc,编译智能合约需要用到这个程序

log_channel=Info message="Using chain" Chain=127.0.0.1:10997 Signer=
log_channel=Info message="Loading Playbook File."
log_channel=Info message="Loading playbook file" path=/root/burrow/tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked filename=/root/burrow/tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked/deploy.yaml
log_channel=Info message="*****Executing Job*****" JobName=defaultAddr Type=Account
log_channel=Info message="Setting Account" account=7CEDE838329CDE8C8302AC31EEBAF0EEA4BE61E5
log_channel=Info message="*****Executing Job*****" JobName=deployStorageK Type=Deploy
log_channel=Info message="Contract path" path=storage.sol
ERROR: exec: "solc": executable file not found in $PATHlog_channel=Info message="JOBS THAT FAILED" count=1
log_channel=Info message="Playbook result" jobNo=0 file=tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked/deploy.yaml error="exec: \"solc\": executable file not found in $PATH" time=3.589948ms

安装一下solc

sudo add-apt-repository ppa:ethereum/ethereum
sudo add-apt-repository ppa:ethereum/ethereum-dev
sudo apt-get update
sudo apt-get install solc

再部署

./burrow deploy  --address $ADDRESS  tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked/deploy.yaml
log_channel=Info message="Using chain" Chain=127.0.0.1:10997 Signer=
log_channel=Info message="Loading Playbook File."
log_channel=Info message="Loading playbook file" path=/root/burrow/tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked filename=/root/burrow/tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked/deploy.yaml
log_channel=Info message="*****Executing Job*****" JobName=defaultAddr Type=Account
log_channel=Info message="Setting Account" account=7CEDE838329CDE8C8302AC31EEBAF0EEA4BE61E5
log_channel=Info message="*****Executing Job*****" JobName=deployStorageK Type=Deploy
log_channel=Info message="Contract path" path=storage.sol
log_channel=Info message="Warning during contract compilation" warning="Warning: This is a pre-release compiler version, please do not use it in production.\n"
log_channel=Info message="Saving Binary" contract=SimpleStorage
log_channel=Info message="Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere"
log_channel=Info message="Using mempool signing"
log_channel=Info message="Tx Return" addr=1E9CCAF198E8CF52FBA313A9F9525BC90D465221 TransactionHash=6fd94cde40379f6f53f2f0ba7c8899ac9ad0d181bef91ed9d55ad6bc4676240c
log_channel=Info message="*****Executing Job*****" JobName=setStorageBaseBool Type=Set
log_channel=Info message="Setting Variable" result=true
log_channel=Info message="*****Executing Job*****" JobName=setStorageBool Type=Call
log_channel=Info message="Function call to constant function, query-contract type job will be faster than call"
log_channel=Info message="Using mempool signing"
log_channel=Info message="No return result value"
log_channel=Info message="*****Executing Job*****" JobName=queryStorageBool Type=QueryContract
log_channel=Info message="Query contract" destination=1E9CCAF198E8CF52FBA313A9F9525BC90D465221 function=getBool data=<nil>
log_channel=Info message="Return Value" value=true
log_channel=Info message="Job Vars" name=retBool value=true
log_channel=Info message="*****Executing Job*****" JobName=assertStorageBool Type=Assert
log_channel=Info message=Assertion key=true relation=eq value=true
log_channel=Info message="Assertion Succeeded" operation="==" key=true value=true
log_channel=Info message="*****Executing Job*****" JobName=setStorageBool2 Type=Call
log_channel=Info message="Function call to constant function, query-contract type job will be faster than call"
log_channel=Info message="Using mempool signing"
log_channel=Info message="No return result value"
log_channel=Info message="*****Executing Job*****" JobName=queryStorageBool2 Type=QueryContract
log_channel=Info message="Query contract" destination=1E9CCAF198E8CF52FBA313A9F9525BC90D465221 function=getBool2 data=<nil>
log_channel=Info message="Return Value" value=true
log_channel=Info message="Job Vars" name=retBool value=true
log_channel=Info message="*****Executing Job*****" JobName=assertStorageBool2 Type=Assert
log_channel=Info message=Assertion key=true relation=eq value=true
log_channel=Info message="Assertion Succeeded" operation="==" key=true value=true
log_channel=Info message="*****Executing Job*****" JobName=setStorageBaseInt Type=Set
log_channel=Info message="Setting Variable" result=50000
log_channel=Info message="*****Executing Job*****" JobName=setStorageInt Type=Call
log_channel=Info message="Function call to constant function, query-contract type job will be faster than call"
log_channel=Info message="Using mempool signing"
log_channel=Info message="No return result value"
log_channel=Info message="*****Executing Job*****" JobName=queryStorageInt Type=QueryContract
log_channel=Info message="Query contract" destination=1E9CCAF198E8CF52FBA313A9F9525BC90D465221 function=getInt data=<nil>
log_channel=Info message="Return Value" value=50000
log_channel=Info message="Job Vars" name=retInt value=50000
log_channel=Info message="*****Executing Job*****" JobName=assertStorageInt Type=Assert
log_channel=Info message=Assertion key=50000 relation=eq value=50000
log_channel=Info message="Assertion Succeeded" operation="==" key=50000 value=50000
log_channel=Info message="*****Executing Job*****" JobName=setStorageBaseUint Type=Set
log_channel=Info message="Setting Variable" result=9999999
log_channel=Info message="*****Executing Job*****" JobName=setStorageUint Type=Call
log_channel=Info message="Function call to constant function, query-contract type job will be faster than call"
log_channel=Info message="Using mempool signing"
log_channel=Info message="No return result value"
log_channel=Info message="*****Executing Job*****" JobName=queryStorageUint Type=QueryContract
log_channel=Info message="Query contract" destination=1E9CCAF198E8CF52FBA313A9F9525BC90D465221 function=getUint data=<nil>
log_channel=Info message="Return Value" value=9999999
log_channel=Info message="Job Vars" name=retUint value=9999999
log_channel=Info message="*****Executing Job*****" JobName=assertStorageUint Type=Assert
log_channel=Info message=Assertion key=9999999 relation=eq value=9999999
log_channel=Info message="Assertion Succeeded" operation="==" key=9999999 value=9999999
log_channel=Info message="*****Executing Job*****" JobName=setStorageBaseAddress Type=Set
log_channel=Info message="Setting Variable" result=1040E6521541DAB4E7EE57F21226DD17CE9F0FB7
log_channel=Info message="*****Executing Job*****" JobName=setStorageAddress Type=Call
log_channel=Info message="Failed to encode abi spec" abi="{\"ContractName\":\"SimpleStorage\",\"SourceFile\":\"storage.sol\",\"CompilerVersion\":\"0.6.3-develop.2020.2.13+commit.c6353774\",\"Abi\":[{\"inputs\":[],\"name\":\"getAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"retAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"retBool\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBool2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"retBool\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBytes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"retBytes\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getInt\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"retInt\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getString\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"retString\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"retUint\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"x\",\"type\":\"address\"}],\"name\":\"setAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"x\",\"type\":\"bool\"}],\"name\":\"setBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"x\",\"type\":\"bool\"}],\"name\":\"setBool2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"x\",\"type\":\"bytes32\"}],\"name\":\"setBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"x\",\"type\":\"int256\"}],\"name\":\"setInt\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"x\",\"type\":\"string\"}],\"name\":\"setString\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"setUint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]}" error="cannot map from string to EVM address"
log_channel=Info message="Failed to encode abi spec" abi="[{\"inputs\":[],\"name\":\"getAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"retAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"retBool\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBool2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"retBool\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBytes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"retBytes\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getInt\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"retInt\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getString\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"retString\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"retUint\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"x\",\"type\":\"address\"}],\"name\":\"setAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"x\",\"type\":\"bool\"}],\"name\":\"setBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"x\",\"type\":\"bool\"}],\"name\":\"setBool2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"x\",\"type\":\"bytes32\"}],\"name\":\"setBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"x\",\"type\":\"int256\"}],\"name\":\"setInt\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"x\",\"type\":\"string\"}],\"name\":\"setString\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"setUint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" error="cannot map from string to EVM address"
log_channel=Info message="ABI Error" data="unsupported value type" bin= dest=1E9CCAF198E8CF52FBA313A9F9525BC90D465221 rawErr="cannot map from string to EVM address"
ERROR:
There has been an error in finding or in using your ABI. ABI's are "Application Binary
Interface" and they are what let us know how to talk to smart contracts.

These little json files can be read by a variety of things which need to talk to smart
contracts so they are quite necessary to be able to find and use properly.

The ABIs are saved after the deploy events. So if there was a glitch in the matrix,
we apologize in advance.

The marmot recovery checklist is...
  * ensure your chain is running and you have enough validators online
  * ensure that your contracts successfully deployed
  * if you used imports or have multiple contracts in one file check the instance
    variable in the deploy and the abi variable in the call/query-contract
  * make sure you're calling or querying the right function
  * make sure you're using the correct variables for job results
log_channel=Info message="JOBS THAT FAILED" count=1
log_channel=Info message="Playbook result" jobNo=0 file=tests/jobs_fixtures/app06-deploy_basic_contract_and_different_solc_types_packed_unpacked/deploy.yaml error="\nThere has been an error in finding or in using your ABI. ABI's are \"Application Binary\nInterface\" and they are what let us know how to talk to smart contracts.\n\nThese little json files can be read by a variety of things which need to talk to smart\ncontracts so they are quite necessary to be able to find and use properly.\n\nThe ABIs are saved after the deploy events. So if there was a glitch in the matrix,\nwe apologize in advance.\n\nThe marmot recovery checklist is...\n  * ensure your chain is running and you have enough validators online\n  * ensure that your contracts successfully deployed\n  * if you used imports or have multiple contracts in one file check the instance\n    variable in the deploy and the abi variable in the call/query-contract\n  * make sure you're calling or querying the right function\n  * make sure you're using the correct variables for job results\n" time=1.400446723s

通过日志观察到已经部署成功了,而且还执行了很多Job,最后执行setStorageAddress的时候报错。

执行出错的job是这样定义的

- name: setStorageBaseAddress
  set:
      val: "1040E6521541DAB4E7EE57F21226DD17CE9F0FB7"

- name: setStorageAddress
  call:
      destination: $deployStorageK
      function: setAddress 
      data:
        - $setStorageBaseAddress

错误信息是cannot map from string to EVM address,setStorageAddress方法接受的address类型的参数 ,而这里给出的是string。
查了下是个bug:https://github.com/hyperledger/burrow/pull/1340

组建网络

先杀掉我们上一步实验启动的burrow进程killall burrow,否则端口会起冲突

生成配置

执行下面的命令后,会生成两个配置文件burrow000.toml、burrow001.toml。如果要生成3个节点的配置,则将-f2 修改为 -f3 ,以此类推。

./burrow spec -f2|./burrow configure -s- --pool

burrow000.toml

ValidatorAddress = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
BurrowDir = ".burrow000"

[GenesisDoc]
  GenesisTime = 2020-04-01T02:12:40Z
  ChainName = "BurrowChain_B8849F"
  [GenesisDoc.Params]
    ProposalThreshold = 3
  [GenesisDoc.GlobalPermissions]
    [GenesisDoc.GlobalPermissions.Base]
      Perms = "send | call | createContract | createAccount | bond | name | proposal | input | batch | hasBase | hasRole"
      SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Accounts]]
    Address = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"EA73778BD492EDBA48D9BF162A26C942D98B7ECB60FCDBC8D2ED7079E7D89859\"}"
    Amount = 99999999999999
    Name = "Full_0"
    [GenesisDoc.Accounts.Permissions]
      [GenesisDoc.Accounts.Permissions.Base]
        Perms = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"
        SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Accounts]]
    Address = "BFC51FC41F4550162E2FF355F571132D6213769C"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"16FB8331816E6C79447BE7C2BA0EEECEF2D6FE0597773AD4C8B21563DB94D668\"}"
    Amount = 99999999999999
    Name = "Full_1"
    [GenesisDoc.Accounts.Permissions]
      [GenesisDoc.Accounts.Permissions.Base]
        Perms = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"
        SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Validators]]
    Address = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"EA73778BD492EDBA48D9BF162A26C942D98B7ECB60FCDBC8D2ED7079E7D89859\"}"
    Amount = 9999999999
    Name = "Full_0"

    [[GenesisDoc.Validators.UnbondTo]]
      Address = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
      PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"EA73778BD492EDBA48D9BF162A26C942D98B7ECB60FCDBC8D2ED7079E7D89859\"}"
      Amount = 9999999999

  [[GenesisDoc.Validators]]
    Address = "BFC51FC41F4550162E2FF355F571132D6213769C"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"16FB8331816E6C79447BE7C2BA0EEECEF2D6FE0597773AD4C8B21563DB94D668\"}"
    Amount = 9999999999
    Name = "Full_1"

    [[GenesisDoc.Validators.UnbondTo]]
      Address = "BFC51FC41F4550162E2FF355F571132D6213769C"
      PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"16FB8331816E6C79447BE7C2BA0EEECEF2D6FE0597773AD4C8B21563DB94D668\"}"
      Amount = 9999999999

[Tendermint]
  Enabled = true
  Seeds = ""
  SeedMode = false
  PersistentPeers = "tcp://dcee77e2804156971bab6f9ca741f3b14c8ed32b@127.0.0.1:26656,tcp://3a6b844760ac1b0629d8de581f87f0514fdecef9@127.0.0.1:26657"
  ListenHost = "127.0.0.1"
  ListenPort = "26656"
  ExternalAddress = ""
  AddrBookStrict = false
  Moniker = "BurrowChain_FAB3C1-CC46B1_Node_36B2954A8683E779B0B719E24327FD0B0ADCB004"
  IdentifyPeers = false
  AuthorizedPeers = ""
  CreateEmptyBlocks = "5m"

[Execution]
  TimeoutFactor = 0.33
  CallStackMaxDepth = 0
  DataStackInitialCapacity = 1024
  DataStackMaxDepth = 0

[Keys]
  GRPCServiceEnabled = true
  AllowBadFilePermissions = false
  RemoteAddress = ""
  KeysDirectory = ".keys"

[RPC]
  [RPC.Info]
    Enabled = true
    ListenHost = "127.0.0.1"
    ListenPort = "26758"
  [RPC.Profiler]
    Enabled = false
    ListenHost = "0.0.0.0"
    ListenPort = "6060"
  [RPC.GRPC]
    Enabled = true
    ListenHost = "127.0.0.1"
    ListenPort = "10997"
  [RPC.Metrics]
    Enabled = false
    ListenHost = "127.0.0.1"
    ListenPort = "9102"
    MetricsPath = "/metrics"
    BlockSampleSize = 100
  [RPC.Web3]
    Enabled = true
    ListenHost = "127.0.0.1"
    ListenPort = "26860"

[Logging]
  Trace = false
  NonBlocking = false
  [Logging.RootSink]
    [Logging.RootSink.Output]
      OutputType = "file"
      Format = "json"
      Path = "burrow000.log"

burrow001.toml

ValidatorAddress = "BFC51FC41F4550162E2FF355F571132D6213769C"
BurrowDir = ".burrow001"

[GenesisDoc]
  GenesisTime = 2020-04-01T02:12:40Z
  ChainName = "BurrowChain_B8849F"
  [GenesisDoc.Params]
    ProposalThreshold = 3
  [GenesisDoc.GlobalPermissions]
    [GenesisDoc.GlobalPermissions.Base]
      Perms = "send | call | createContract | createAccount | bond | name | proposal | input | batch | hasBase | hasRole"
      SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Accounts]]
    Address = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"EA73778BD492EDBA48D9BF162A26C942D98B7ECB60FCDBC8D2ED7079E7D89859\"}"
    Amount = 99999999999999
    Name = "Full_0"
    [GenesisDoc.Accounts.Permissions]
      [GenesisDoc.Accounts.Permissions.Base]
        Perms = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"
        SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Accounts]]
    Address = "BFC51FC41F4550162E2FF355F571132D6213769C"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"16FB8331816E6C79447BE7C2BA0EEECEF2D6FE0597773AD4C8B21563DB94D668\"}"
    Amount = 99999999999999
    Name = "Full_1"
    [GenesisDoc.Accounts.Permissions]
      [GenesisDoc.Accounts.Permissions.Base]
        Perms = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"
        SetBit = "root | send | call | createContract | createAccount | bond | name | proposal | input | batch | identify | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole"

  [[GenesisDoc.Validators]]
    Address = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"EA73778BD492EDBA48D9BF162A26C942D98B7ECB60FCDBC8D2ED7079E7D89859\"}"
    Amount = 9999999999
    Name = "Full_0"

    [[GenesisDoc.Validators.UnbondTo]]
      Address = "74E0EBA611656F201DC1BF1A5FA695D12AC749E6"
      PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"EA73778BD492EDBA48D9BF162A26C942D98B7ECB60FCDBC8D2ED7079E7D89859\"}"
      Amount = 9999999999

  [[GenesisDoc.Validators]]
    Address = "BFC51FC41F4550162E2FF355F571132D6213769C"
    PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"16FB8331816E6C79447BE7C2BA0EEECEF2D6FE0597773AD4C8B21563DB94D668\"}"
    Amount = 9999999999
    Name = "Full_1"

    [[GenesisDoc.Validators.UnbondTo]]
      Address = "BFC51FC41F4550162E2FF355F571132D6213769C"
      PublicKey = "{\"CurveType\":\"ed25519\",\"PublicKey\":\"16FB8331816E6C79447BE7C2BA0EEECEF2D6FE0597773AD4C8B21563DB94D668\"}"
      Amount = 9999999999

[Tendermint]
  Enabled = true
  Seeds = ""
  SeedMode = false
  PersistentPeers = "tcp://dcee77e2804156971bab6f9ca741f3b14c8ed32b@127.0.0.1:26656,tcp://3a6b844760ac1b0629d8de581f87f0514fdecef9@127.0.0.1:26657"
  ListenHost = "127.0.0.1"
  ListenPort = "26657"
  ExternalAddress = ""
  AddrBookStrict = false
  Moniker = "BurrowChain_FAB3C1-CC46B1_Node_36B2954A8683E779B0B719E24327FD0B0ADCB004"
  IdentifyPeers = false
  AuthorizedPeers = ""
  CreateEmptyBlocks = "5m"

[Execution]
  TimeoutFactor = 0.33
  CallStackMaxDepth = 0
  DataStackInitialCapacity = 1024
  DataStackMaxDepth = 0

[Keys]
  GRPCServiceEnabled = true
  AllowBadFilePermissions = false
  RemoteAddress = ""
  KeysDirectory = ".keys"

[RPC]
  [RPC.Info]
    Enabled = true
    ListenHost = "127.0.0.1"
    ListenPort = "26759"
  [RPC.Profiler]
    Enabled = false
    ListenHost = "0.0.0.0"
    ListenPort = "6060"
  [RPC.GRPC]
    Enabled = true
    ListenHost = "127.0.0.1"
    ListenPort = "10998"
  [RPC.Metrics]
    Enabled = false
    ListenHost = "127.0.0.1"
    ListenPort = "9103"
    MetricsPath = "/metrics"
    BlockSampleSize = 100
  [RPC.Web3]
    Enabled = true
    ListenHost = "127.0.0.1"
    ListenPort = "26861"

[Logging]
  Trace = false
  NonBlocking = false
  [Logging.RootSink]
    [Logging.RootSink.Output]
      OutputType = "file"
      Format = "json"
      Path = "burrow001.log"
启动第一个节点
nohup ./burrow start --config=burrow000.toml >/dev/null 2>&1 &
启动第二个节点
nohup ./burrow start --config=burrow001.toml >/dev/null 2>&1 &
检查是否连接成功
curl -s 127.0.0.1:26758/consensus
curl -s 127.0.0.1:26759/consensus
curl -s 127.0.0.1:26759/consensus
{
  "jsonrpc": "2.0",
  "id": "",
  "result": {
    "round_state": {
      "height": "2",
      "round": "0",
      "step": 2,
      "start_time": "2020-04-01T02:21:10.589956473Z",
      "commit_time": "2020-04-01T02:21:10.259956473Z",
      "validators": {
        "validators": [
          {
            "address": "74E0EBA611656F201DC1BF1A5FA695D12AC749E6",
            "pub_key": {
              "type": "tendermint/PubKeyEd25519",
              "value": "6nN3i9SS7bpI2b8WKibJQtmLfstg/NvI0u1weefYmFk="
            },
            "voting_power": "9999999999",
            "proposer_priority": "0"
          },
          {
            "address": "BFC51FC41F4550162E2FF355F571132D6213769C",
            "pub_key": {
              "type": "tendermint/PubKeyEd25519",
              "value": "FvuDMYFubHlEe+fCug7uzvLW/gWXdzrUyLIVY9uU1mg="
            },
            "voting_power": "9999999999",
            "proposer_priority": "0"
          }
        ],
        "proposer": {
          "address": "BFC51FC41F4550162E2FF355F571132D6213769C",
          "pub_key": {
            "type": "tendermint/PubKeyEd25519",
            "value": "FvuDMYFubHlEe+fCug7uzvLW/gWXdzrUyLIVY9uU1mg="
          },
          "voting_power": "9999999999",
          "proposer_priority": "0"
        }
      },
      "proposal": null,
      "proposal_block": null,
      "proposal_block_parts": null,
      "locked_round": "-1",
      "locked_block": null,
      "locked_block_parts": null,
      "valid_round": "-1",
      "valid_block": null,
      "valid_block_parts": null,
      "votes": [
        {
          "round": "0",
          "prevotes": [
            "nil-Vote",
            "nil-Vote"
          ],
          "prevotes_bit_array": "BA{2:__} 0/19999999998 = 0.00",
          "precommits": [
            "nil-Vote",
            "nil-Vote"
          ],
          "precommits_bit_array": "BA{2:__} 0/19999999998 = 0.00"
        },
        {
          "round": "1",
          "prevotes": [
            "nil-Vote",
            "nil-Vote"
          ],
          "prevotes_bit_array": "BA{2:__} 0/19999999998 = 0.00",
          "precommits": [
            "nil-Vote",
            "nil-Vote"
          ],
          "precommits_bit_array": "BA{2:__} 0/19999999998 = 0.00"
        }
      ],
      "commit_round": "-1",
      "last_commit": {
        "votes": [
          "Vote{0:74E0EBA61165 1/00/2(Precommit) AC20689E6673 3F18B4554714 @ 2020-04-01T02:21:10.156997478Z}",
          "Vote{1:BFC51FC41F45 1/00/2(Precommit) AC20689E6673 EA6A5F6E53E0 @ 2020-04-01T02:21:09.951555109Z}"
        ],
        "votes_bit_array": "BA{2:xx} 19999999998/19999999998 = 1.00",
        "peer_maj_23s": {}
      },
      "last_validators": {
        "validators": [
          {
            "address": "74E0EBA611656F201DC1BF1A5FA695D12AC749E6",
            "pub_key": {
              "type": "tendermint/PubKeyEd25519",
              "value": "6nN3i9SS7bpI2b8WKibJQtmLfstg/NvI0u1weefYmFk="
            },
            "voting_power": "9999999999",
            "proposer_priority": "-9999999999"
          },
          {
            "address": "BFC51FC41F4550162E2FF355F571132D6213769C",
            "pub_key": {
              "type": "tendermint/PubKeyEd25519",
              "value": "FvuDMYFubHlEe+fCug7uzvLW/gWXdzrUyLIVY9uU1mg="
            },
            "voting_power": "9999999999",
            "proposer_priority": "9999999999"
          }
        ],
        "proposer": {
          "address": "74E0EBA611656F201DC1BF1A5FA695D12AC749E6",
          "pub_key": {
            "type": "tendermint/PubKeyEd25519",
            "value": "6nN3i9SS7bpI2b8WKibJQtmLfstg/NvI0u1weefYmFk="
          },
          "voting_power": "9999999999",
          "proposer_priority": "-9999999999"
        }
      },
      "triggered_timeout_precommit": false
    },
    "peers": [
      {
        "node_address": "dcee77e2804156971bab6f9ca741f3b14c8ed32b@dcee77e2804156971bab6f9ca741f3b14c8ed32b@127.0.0.1:26656",
        "peer_state": {
          "round_state": {
            "height": "2",
            "round": "0",
            "step": 1,
            "start_time": "2020-04-01T02:21:10.25925951Z",
            "proposal": false,
            "proposal_block_parts_header": {
              "total": "0",
              "hash": ""
            },
            "proposal_block_parts": null,
            "proposal_pol_round": "-1",
            "proposal_pol": "__",
            "prevotes": "__",
            "precommits": "__",
            "last_commit_round": "0",
            "last_commit": "xx",
            "catchup_commit_round": "-1",
            "catchup_commit": "__"
          },
          "stats": {
            "votes": "2",
            "block_parts": "1"
          }
        }
      }
    ]
  }
}#
交易注意事项

需要指定配置文件和验证着

burrow tx -v0 -c burrow000.toml formulate send -s $SENDER -t $RECIPIENT -a $AMOUNT  > tx.json
burrow tx -v0 -c burrow000.toml commit --file tx.json
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1444. Elephpotamus Time limit: 0.5 second Memory limit: 64 MB Harry Potter is taking an examination in Care for Magical Creatures. His task is to feed a dwarf elephpotamus. Harry remembers that elephpotamuses are very straightforward and imperturbable. In fact, they are so straightforward that always move along a straight line and they are so imperturbable that only move when attracted by something really tasty. In addition, if an elephpotamus stumbles into a chain of its own footprints, it falls into a stupor and refuses to go anywhere. According to Hagrid, elephpotamuses usually get back home moving along their footprints. This is why they never cross them, otherwise they may get lost. When an elephpotamus sees its footprints, it tries to remember in detail all its movements since leaving home (this is also the reason why they move along straight lines only, this way it is easier to memorize). Basing on this information, the animal calculates in which direction its burrow is situated, then turns and goes straight to it. It takes some (rather large) time for an elephpotamus to perform these calculations. And what some ignoramuses recognize as a stupor is in fact a demonstration of outstanding calculating abilities of this wonderful, though a bit slow-witted creature. Elephpotamuses' favorite dainty is elephant pumpkins, and some of such pumpkins grow on the lawn where Harry is to take his exam. At the start of the exam, Hagrid will drag the elephpotamus to one of the pumpkins. Having fed the animal with a pumpkin, Harry can direct it to any of the remaining pumpkins. In order to pass the exam, Harry must lead the elephpotamus so that it eats as many pumpkins as possible before it comes across its footprints. Input The first input line contains the number of pumpkins on the lawn N (3 ≤ N ≤ 30000). The pumpkins are numbered from 1 to N, the number one being assigned to the pumpkin to which the animal is brought at the start of the trial. In the next N lines, the coordinates of the pumpkins are given in the order corresponding to their numbers. All the coordinates are integers in the range from −1000 to 1000. It is guaranteed that there are no two pumpkins at the same location and there is no straight line passing through all the pumpkins. Output In the first line write the maximal number K of pumpkins that can be fed to the elephpotamus. In the next K lines, output the order in which the animal will eat them, giving one number in a line. The first number in this sequence must always be 1.写一段Java完成此目的
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值