Ecoer Logo
VOTING POWER100.00%
DOWNVOTE POWER100.00%
RESOURCE CREDITS100.00%
REPUTATION PROGRESS0.00%
Net Worth
0.007USD
STEEM
0.001STEEM
SBD
0.000SBD
Effective Power
5.007SP
├── Own SP
0.124SP
└── Incoming Deleg
+4.883SP

Detailed Balance

STEEM
balance
0.001STEEM
market_balance
0.000STEEM
savings_balance
0.000STEEM
reward_steem_balance
0.000STEEM
STEEM POWER
Own SP
0.124SP
Delegated Out
0.000SP
Delegation In
4.883SP
Effective Power
5.007SP
Reward SP (pending)
0.000SP
SBD
sbd_balance
0.000SBD
sbd_conversions
0.000SBD
sbd_market_balance
0.000SBD
savings_sbd_balance
0.000SBD
reward_sbd_balance
0.000SBD
{
  "balance": "0.001 STEEM",
  "savings_balance": "0.000 STEEM",
  "reward_steem_balance": "0.000 STEEM",
  "vesting_shares": "202.265526 VESTS",
  "delegated_vesting_shares": "0.000000 VESTS",
  "received_vesting_shares": "7941.394280 VESTS",
  "sbd_balance": "0.000 SBD",
  "savings_sbd_balance": "0.000 SBD",
  "reward_sbd_balance": "0.000 SBD",
  "conversions": []
}

Account Info

nameeoswing
id1132713
rank1,262,662
reputation507486445
created2018-09-07T14:26:24
recovery_accountsteem
proxyNone
post_count22
comment_count0
lifetime_vote_count0
witnesses_voted_for0
last_post2019-02-21T08:25:24
last_root_post2019-02-21T08:25:24
last_vote_time2018-12-05T09:23:21
proxied_vsf_votes0, 0, 0, 0
can_vote1
voting_power0
delayed_votes0
balance0.001 STEEM
savings_balance0.000 STEEM
sbd_balance0.000 SBD
savings_sbd_balance0.000 SBD
vesting_shares202.265526 VESTS
delegated_vesting_shares0.000000 VESTS
received_vesting_shares7941.394280 VESTS
reward_vesting_balance0.000000 VESTS
vesting_balance0.000 STEEM
vesting_withdraw_rate0.000000 VESTS
next_vesting_withdrawal1969-12-31T23:59:59
withdrawn0
to_withdraw0
withdraw_routes0
savings_withdraw_requests0
last_account_recovery1970-01-01T00:00:00
reset_accountnull
last_owner_update1970-01-01T00:00:00
last_account_update2018-09-07T14:42:21
minedNo
sbd_seconds0
sbd_last_interest_payment1970-01-01T00:00:00
savings_sbd_last_interest_payment1970-01-01T00:00:00
{
  "id": 1132713,
  "name": "eoswing",
  "owner": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
      [
        "STM6yG6ezPfMj8DjrTSLhH8FjBjP1uyZrHteE8siSaxfkCfCguQFz",
        1
      ]
    ]
  },
  "active": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
      [
        "STM7VzZaD1MTmTRrCxuEaJTf6exRKsncya3gZD6tQd4FwptpWwwj3",
        1
      ]
    ]
  },
  "posting": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
      [
        "STM7yc8CYF437A32GNcG47MG4R26RNQ24tVHcc9Vg7ip93tnaaaJg",
        1
      ]
    ]
  },
  "memo_key": "STM6Dw6kWbk4GdGtf3tFBL2ci5egtoyJ3UByF6MVENxXRWU83RMDP",
  "json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmaQM1M6ra6es2eRgwgKgTQ2fDExkGkKSmBfyWXXmJQKiZ/eoswing-logo-256b.png\",\"website\":\"https://eoswing.io\",\"name\":\"eoswing\"}}",
  "posting_json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmaQM1M6ra6es2eRgwgKgTQ2fDExkGkKSmBfyWXXmJQKiZ/eoswing-logo-256b.png\",\"website\":\"https://eoswing.io\",\"name\":\"eoswing\"}}",
  "proxy": "",
  "last_owner_update": "1970-01-01T00:00:00",
  "last_account_update": "2018-09-07T14:42:21",
  "created": "2018-09-07T14:26:24",
  "mined": false,
  "recovery_account": "steem",
  "last_account_recovery": "1970-01-01T00:00:00",
  "reset_account": "null",
  "comment_count": 0,
  "lifetime_vote_count": 0,
  "post_count": 22,
  "can_vote": true,
  "voting_manabar": {
    "current_mana": "8143659806",
    "last_update_time": 1779062478
  },
  "downvote_manabar": {
    "current_mana": 2035914951,
    "last_update_time": 1779062478
  },
  "voting_power": 0,
  "balance": "0.001 STEEM",
  "savings_balance": "0.000 STEEM",
  "sbd_balance": "0.000 SBD",
  "sbd_seconds": "0",
  "sbd_seconds_last_update": "1970-01-01T00:00:00",
  "sbd_last_interest_payment": "1970-01-01T00:00:00",
  "savings_sbd_balance": "0.000 SBD",
  "savings_sbd_seconds": "0",
  "savings_sbd_seconds_last_update": "1970-01-01T00:00:00",
  "savings_sbd_last_interest_payment": "1970-01-01T00:00:00",
  "savings_withdraw_requests": 0,
  "reward_sbd_balance": "0.000 SBD",
  "reward_steem_balance": "0.000 STEEM",
  "reward_vesting_balance": "0.000000 VESTS",
  "reward_vesting_steem": "0.000 STEEM",
  "vesting_shares": "202.265526 VESTS",
  "delegated_vesting_shares": "0.000000 VESTS",
  "received_vesting_shares": "7941.394280 VESTS",
  "vesting_withdraw_rate": "0.000000 VESTS",
  "next_vesting_withdrawal": "1969-12-31T23:59:59",
  "withdrawn": 0,
  "to_withdraw": 0,
  "withdraw_routes": 0,
  "curation_rewards": 0,
  "posting_rewards": 0,
  "proxied_vsf_votes": [
    0,
    0,
    0,
    0
  ],
  "witnesses_voted_for": 0,
  "last_post": "2019-02-21T08:25:24",
  "last_root_post": "2019-02-21T08:25:24",
  "last_vote_time": "2018-12-05T09:23:21",
  "post_bandwidth": 0,
  "pending_claimed_accounts": 0,
  "vesting_balance": "0.000 STEEM",
  "reputation": 507486445,
  "transfer_history": [],
  "market_history": [],
  "post_history": [],
  "vote_history": [],
  "other_history": [],
  "witness_votes": [],
  "tags_usage": [],
  "guest_bloggers": [],
  "rank": 1262662
}

Withdraw Routes

IncomingOutgoing
Empty
Empty
{
  "incoming": [],
  "outgoing": []
}
From Date
To Date
steemdelegated 4.883 SP to @eoswing
2026/05/18 00:01:18
delegatorsteem
delegateeeoswing
vesting shares7941.394280 VESTS
Transaction InfoBlock #106143172/Trx 3bf4d29f3b5ac8483df6167494edc9665fad010c
View Raw JSON Data
{
  "trx_id": "3bf4d29f3b5ac8483df6167494edc9665fad010c",
  "block": 106143172,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2026-05-18T00:01:18",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "7941.394280 VESTS"
    }
  ]
}
steemdelegated 3.215 SP to @eoswing
2026/05/12 02:54:06
delegatorsteem
delegateeeoswing
vesting shares5229.183875 VESTS
Transaction InfoBlock #105974585/Trx db26b803e5a322ff4d1bf04f07e9b4be49108bee
View Raw JSON Data
{
  "trx_id": "db26b803e5a322ff4d1bf04f07e9b4be49108bee",
  "block": 105974585,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2026-05-12T02:54:06",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "5229.183875 VESTS"
    }
  ]
}
steemdelegated 4.890 SP to @eoswing
2026/04/25 23:22:33
delegatorsteem
delegateeeoswing
vesting shares7953.910036 VESTS
Transaction InfoBlock #105510829/Trx 9f92efae4d9cf032b9d05c1981f1805d5b2656c8
View Raw JSON Data
{
  "trx_id": "9f92efae4d9cf032b9d05c1981f1805d5b2656c8",
  "block": 105510829,
  "trx_in_block": 0,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2026-04-25T23:22:33",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "7953.910036 VESTS"
    }
  ]
}
steemdelegated 3.241 SP to @eoswing
2026/01/23 07:10:21
delegatorsteem
delegateeeoswing
vesting shares5270.730694 VESTS
Transaction InfoBlock #102851055/Trx d53f4bb77aeb5f25810969ae7eabc1fda55c7047
View Raw JSON Data
{
  "trx_id": "d53f4bb77aeb5f25810969ae7eabc1fda55c7047",
  "block": 102851055,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2026-01-23T07:10:21",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "5270.730694 VESTS"
    }
  ]
}
steemdelegated 3.342 SP to @eoswing
2024/12/17 02:29:57
delegatorsteem
delegateeeoswing
vesting shares5434.949891 VESTS
Transaction InfoBlock #91297475/Trx aa03f1858949b318da23c529b36bfbd9ad9cdecf
View Raw JSON Data
{
  "trx_id": "aa03f1858949b318da23c529b36bfbd9ad9cdecf",
  "block": 91297475,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2024-12-17T02:29:57",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "5434.949891 VESTS"
    }
  ]
}
steemdelegated 3.446 SP to @eoswing
2023/11/13 18:12:30
delegatorsteem
delegateeeoswing
vesting shares5604.083423 VESTS
Transaction InfoBlock #79851673/Trx 833cd1a8397b61080cad0f882702141f10ba3536
View Raw JSON Data
{
  "trx_id": "833cd1a8397b61080cad0f882702141f10ba3536",
  "block": 79851673,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2023-11-13T18:12:30",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "5604.083423 VESTS"
    }
  ]
}
steemdelegated 5.252 SP to @eoswing
2023/09/21 21:33:12
delegatorsteem
delegateeeoswing
vesting shares8541.362209 VESTS
Transaction InfoBlock #78347496/Trx 76c8dfd105a989a7eb69c206bd23c35e931538b6
View Raw JSON Data
{
  "trx_id": "76c8dfd105a989a7eb69c206bd23c35e931538b6",
  "block": 78347496,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2023-09-21T21:33:12",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "8541.362209 VESTS"
    }
  ]
}
steemdelegated 5.388 SP to @eoswing
2022/11/03 11:23:21
delegatorsteem
delegateeeoswing
vesting shares8763.043647 VESTS
Transaction InfoBlock #69112886/Trx a83bb5a48e747aba0012caa41c937f6a487ad50d
View Raw JSON Data
{
  "trx_id": "a83bb5a48e747aba0012caa41c937f6a487ad50d",
  "block": 69112886,
  "trx_in_block": 5,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2022-11-03T11:23:21",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "8763.043647 VESTS"
    }
  ]
}
steemdelegated 5.523 SP to @eoswing
2022/01/17 10:40:42
delegatorsteem
delegateeeoswing
vesting shares8983.576878 VESTS
Transaction InfoBlock #60809080/Trx 7d2283a1faec152250cca34368a68f9f03ee9090
View Raw JSON Data
{
  "trx_id": "7d2283a1faec152250cca34368a68f9f03ee9090",
  "block": 60809080,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2022-01-17T10:40:42",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "8983.576878 VESTS"
    }
  ]
}
steemdelegated 5.636 SP to @eoswing
2021/06/14 00:36:42
delegatorsteem
delegateeeoswing
vesting shares9167.345536 VESTS
Transaction InfoBlock #54607483/Trx 2a7b6d8eede1d19d8db3e3ba603b372986464d90
View Raw JSON Data
{
  "trx_id": "2a7b6d8eede1d19d8db3e3ba603b372986464d90",
  "block": 54607483,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2021-06-14T00:36:42",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "9167.345536 VESTS"
    }
  ]
}
steemdelegated 5.752 SP to @eoswing
2020/12/11 10:55:51
delegatorsteem
delegateeeoswing
vesting shares9354.767510 VESTS
Transaction InfoBlock #49354950/Trx ab25acb0e73b2dcea57364088fe5e7dbe61a1bc6
View Raw JSON Data
{
  "trx_id": "ab25acb0e73b2dcea57364088fe5e7dbe61a1bc6",
  "block": 49354950,
  "trx_in_block": 0,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-12-11T10:55:51",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "9354.767510 VESTS"
    }
  ]
}
steemdelegated 1.176 SP to @eoswing
2020/12/06 04:33:09
delegatorsteem
delegateeeoswing
vesting shares1912.543513 VESTS
Transaction InfoBlock #49206516/Trx b35dbbdec39184b1df9cbbd8827e692f64cb88f3
View Raw JSON Data
{
  "trx_id": "b35dbbdec39184b1df9cbbd8827e692f64cb88f3",
  "block": 49206516,
  "trx_in_block": 3,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-12-06T04:33:09",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "1912.543513 VESTS"
    }
  ]
}
steemdelegated 5.756 SP to @eoswing
2020/12/05 14:34:06
delegatorsteem
delegateeeoswing
vesting shares9360.975364 VESTS
Transaction InfoBlock #49190050/Trx f5c4ad344225978e4b7ba39a5814b0a36d8dd495
View Raw JSON Data
{
  "trx_id": "f5c4ad344225978e4b7ba39a5814b0a36d8dd495",
  "block": 49190050,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-12-05T14:34:06",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "9360.975364 VESTS"
    }
  ]
}
steemdelegated 1.181 SP to @eoswing
2020/11/02 15:09:51
delegatorsteem
delegateeeoswing
vesting shares1920.017158 VESTS
Transaction InfoBlock #48257239/Trx 7488c75635b4cc94b0a89e2b4339aec509fff359
View Raw JSON Data
{
  "trx_id": "7488c75635b4cc94b0a89e2b4339aec509fff359",
  "block": 48257239,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-11-02T15:09:51",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "1920.017158 VESTS"
    }
  ]
}
steemdelegated 5.880 SP to @eoswing
2020/05/09 05:30:12
delegatorsteem
delegateeeoswing
vesting shares9563.780723 VESTS
Transaction InfoBlock #43216759/Trx 717e4e0f6bd58ecc571f73a6030c7511cec10496
View Raw JSON Data
{
  "trx_id": "717e4e0f6bd58ecc571f73a6030c7511cec10496",
  "block": 43216759,
  "trx_in_block": 14,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-05-09T05:30:12",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "9563.780723 VESTS"
    }
  ]
}
steemdelegated 1.201 SP to @eoswing
2020/05/08 09:04:18
delegatorsteem
delegateeeoswing
vesting shares1953.311140 VESTS
Transaction InfoBlock #43192817/Trx aa8ce73240e6fb9b06d006f8b166a26e88296dc6
View Raw JSON Data
{
  "trx_id": "aa8ce73240e6fb9b06d006f8b166a26e88296dc6",
  "block": 43192817,
  "trx_in_block": 21,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-05-08T09:04:18",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "1953.311140 VESTS"
    }
  ]
}
steemdelegated 5.884 SP to @eoswing
2020/04/27 05:57:39
delegatorsteem
delegateeeoswing
vesting shares9570.540567 VESTS
Transaction InfoBlock #42880178/Trx 430401a05a0f1c454a1fed7fd5a11b5e8e0a5474
View Raw JSON Data
{
  "trx_id": "430401a05a0f1c454a1fed7fd5a11b5e8e0a5474",
  "block": 42880178,
  "trx_in_block": 10,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2020-04-27T05:57:39",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "9570.540567 VESTS"
    }
  ]
}
2019/09/07 15:32:36
parent authoreoswing
parent permlinkeos-testnet
authorsteemitboard
permlinksteemitboard-notify-eoswing-20190907t153235000z
title
bodyCongratulations @eoswing! You received a personal award! <table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@eoswing/birthday1.png</td><td>Happy Birthday! - You are on the Steem blockchain for 1 year!</td></tr></table> <sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@eoswing) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=eoswing)_</sub> ###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!
json metadata{"image":["https://steemitboard.com/img/notify.png"]}
Transaction InfoBlock #36216965/Trx 3fda77e8d03018eddd9d1b8a83edd2712876875e
View Raw JSON Data
{
  "trx_id": "3fda77e8d03018eddd9d1b8a83edd2712876875e",
  "block": 36216965,
  "trx_in_block": 11,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-09-07T15:32:36",
  "op": [
    "comment",
    {
      "parent_author": "eoswing",
      "parent_permlink": "eos-testnet",
      "author": "steemitboard",
      "permlink": "steemitboard-notify-eoswing-20190907t153235000z",
      "title": "",
      "body": "Congratulations @eoswing! You received a personal award!\n\n<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@eoswing/birthday1.png</td><td>Happy Birthday! - You are on the Steem blockchain for 1 year!</td></tr></table>\n\n<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@eoswing) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=eoswing)_</sub>\n\n\n###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!",
      "json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}"
    }
  ]
}
steemdelegated 6.005 SP to @eoswing
2019/05/23 10:58:30
delegatorsteem
delegateeeoswing
vesting shares9765.999440 VESTS
Transaction InfoBlock #33157373/Trx 9419f9e86e3d20696bdcbbfca4812c1c17dadcce
View Raw JSON Data
{
  "trx_id": "9419f9e86e3d20696bdcbbfca4812c1c17dadcce",
  "block": 33157373,
  "trx_in_block": 12,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-05-23T10:58:30",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "9765.999440 VESTS"
    }
  ]
}
steemdelegated 18.283 SP to @eoswing
2019/05/04 00:05:00
delegatorsteem
delegateeeoswing
vesting shares29736.790205 VESTS
Transaction InfoBlock #32597415/Trx 2823a39230fa128508f74bb4ff67c640d0759bc3
View Raw JSON Data
{
  "trx_id": "2823a39230fa128508f74bb4ff67c640d0759bc3",
  "block": 32597415,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-05-04T00:05:00",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "29736.790205 VESTS"
    }
  ]
}
eoswingpublished a new post: eos-testnet
2019/02/21 08:25:24
parent author
parent permlinkeos
authoreoswing
permlinkeos-testnet
title手把手教你玩eos:在公共Testnet上部署和测试智能合约
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![手把手-公众号.jpg](https://cdn.steemitimages.com/DQmS1PzgVtAVWW9ZufURDA7ZVQRehavgU23TWmFzPDJJQTr/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十九篇。本篇教程演示如何使用EOSFactory在公共testnet上部署和测试EOS智能合约,例如Jungle Testnet或CryptoKylin Testnet。 0.2 学习内容 注册账号 部署和测试智能合约 两则技巧 0.3 机器环境 ●笔记本电脑 ●操作系统:Windows 10 1. 注册账号 1.1 在丛林测试网上注册账号 我们在eosfactory中注册账号: cd /mnt/f/EOS/eosfactory python3 utils/register_testnet.py http://jungle2.cryptolions.io:80 myjungle ![eost19-01.png](https://cdn.steemitimages.com/DQmXJR48uqUW5dEtkuEZBCDDJmvrYj4nULxbvPq4U727bwz/eost19-01.png) 将对应的账号名和公钥复制下来。 在浏览器中打开丛林测试网 Jungle Testnet 2.0: https://monitor.jungletestnet.io/ 点击“Create Account”,在弹出对话框中输入对应账户名和公钥(注意,不是私钥),完成创建。 ![eost19-02.png](https://cdn.steemitimages.com/DQmYNCBVmEuGMDGE2Ld3sbKyLYZ75T3qQPTZubXhD2CcsF4/eost19-02.png) 完成人机身份验证(注意,如果网络不好的,可能会一直刷不出来) 然后,点击Create,完成账户注册。 因为是公共测试网,而不是本地节点,为了方便合约开发。 我们要通过水龙头,给该账户申请一些EOS,然后抵押资源。 确保RAM,cpu,net等资源充足。 在https://monitor.jungletestnet.io/上点击“faucet”菜单获取。6小时可以获取一次。 ![eost19-03.png](https://cdn.steemitimages.com/DQmPzAbpVd98C1JMJZfrRhkLkjVTXiTMfDfeZsoZrUf8qWh/eost19-03.png) 准备好了,我们再回到命令行,在提示符后面输入 go ![eost19-04.png](https://cdn.steemitimages.com/DQmS9bP8YRxbA5D3aZGyTzBisLW6koAzHCJra5V26gcJePp/eost19-04.png) 验证注册完成。 1.2 在麒麟测试网上注册账号 麒麟测试网上注册要更自动化一些。 三个参数分别是:对应的水龙头网网址,公共节点网址,账号别名。 然后,就会自动完成注册和水龙头获取代币。 python3 utils/register_testnet_via_faucet.py http://faucet.cryptokylin.io http://kylin.fn.eosbixin.com mykylin ![eost19-05.png](https://cdn.steemitimages.com/DQmbdoxPMduAhJwxNodTSmfVUCvB7LCMLmihsJddkL8jZgn/eost19-05.png) 1.3 查看测试网账号 python3 utils/testnets.py ![eost19-06.png](https://cdn.steemitimages.com/DQmQjT7kQvjy39yQ9cM8JtKVsHTUP75LD96en6NjdprUgCN/eost19-06.png) 2. 部署和测试智能合约 2.1 创建新的智能合约 目前,还只有 03_tic_tac_toe 模板支持测试网。所以我们基于这个模板创建 python3 utils/create_project.py foo_bar_net 03_tic_tac_toe --vsc ![eost19-07.png](https://cdn.steemitimages.com/DQmeCCMb13pqGFCrtNfjt4LY49kxpQWoRmvz3F3nkApd4va/eost19-07.png) 2.2 在丛林测试网上测试 python3 tests/unittest1.py myjungle ![eost19-08.png](https://cdn.steemitimages.com/DQmeRaZNWySCwHDF5uWhtVyvzZngomK2fbbRpYbdotXoDAq/eost19-08.png) python3 tests/test1.py myjungle ![eost19-09.png](https://cdn.steemitimages.com/DQmeUDpvVC3LH8jQY1Z8YwSjmuJxoLDBjGgyywU4gp5Y4vX/eost19-09.png) 2.3 在麒麟测试网上测试 python3 tests/unittest1.py mykylin ![eost19-10.png](https://cdn.steemitimages.com/DQmXGsiZQQBNcpNvvQgjxjQAfu5pwqjrFhYjFo4ozRwwy8b/eost19-10.png) python3 tests/test1.py mykylin ![eost19-11.png](https://cdn.steemitimages.com/DQmWhRUwYkPYgLtDkrhZeQ3CELvL3gachG8j7ZZFakt9Byk/eost19-11.png) 3 两则技巧 3.1 清空账号 测试网中建立的账号在测试时是重复利用的。 如果您要从头开始运行测试,即把现有帐户从EOSFactory缓存中删除并替换为另一组新创建的帐户,请在命令后面添加该参数: -r python3 tests/unittest1.py myjungle -r 3.2 使用自己原来注册好的测试网账号 如果您在公共测试网上有帐户,则可以跳过使用EOSFactory注册账号,并直接运行单元测试。 方法是使用-t(或–testnet)选项。 此选项需要四个参数: ●提供对testnet的访问的公共节点的URL,例如http://kylin.fn.eosbixin.com, ●您的帐户名称,在testnet上注册, ●您帐户的Owner私钥, ●您帐户的Active私钥。 命令类似于: python3 tests/unittest1.py -t http://kylin.fn.eosbixin.com dgxo1uyhoytn 5JE9XSurh4Bmdw8Ynz72Eh6ZCKrxf63SmQWKrYJSXf1dEnoiKFY 5JgLo7jZhmY4huDNXwExmaWQJqyS1hGZrnSjECcpWwGU25Ym8tA 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: ●与公共Testnet交互: http://eosfactory.io/build/html/tutorials/05.InteractingWithPublicTestnet.html 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmS1PzgVtAVWW9ZufURDA7ZVQRehavgU23TWmFzPDJJQTr/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.jpg","https://cdn.steemitimages.com/DQmXJR48uqUW5dEtkuEZBCDDJmvrYj4nULxbvPq4U727bwz/eost19-01.png","https://cdn.steemitimages.com/DQmYNCBVmEuGMDGE2Ld3sbKyLYZ75T3qQPTZubXhD2CcsF4/eost19-02.png","https://cdn.steemitimages.com/DQmPzAbpVd98C1JMJZfrRhkLkjVTXiTMfDfeZsoZrUf8qWh/eost19-03.png","https://cdn.steemitimages.com/DQmS9bP8YRxbA5D3aZGyTzBisLW6koAzHCJra5V26gcJePp/eost19-04.png","https://cdn.steemitimages.com/DQmbdoxPMduAhJwxNodTSmfVUCvB7LCMLmihsJddkL8jZgn/eost19-05.png","https://cdn.steemitimages.com/DQmQjT7kQvjy39yQ9cM8JtKVsHTUP75LD96en6NjdprUgCN/eost19-06.png","https://cdn.steemitimages.com/DQmeCCMb13pqGFCrtNfjt4LY49kxpQWoRmvz3F3nkApd4va/eost19-07.png","https://cdn.steemitimages.com/DQmeRaZNWySCwHDF5uWhtVyvzZngomK2fbbRpYbdotXoDAq/eost19-08.png","https://cdn.steemitimages.com/DQmeUDpvVC3LH8jQY1Z8YwSjmuJxoLDBjGgyywU4gp5Y4vX/eost19-09.png","https://cdn.steemitimages.com/DQmXGsiZQQBNcpNvvQgjxjQAfu5pwqjrFhYjFo4ozRwwy8b/eost19-10.png","https://cdn.steemitimages.com/DQmWhRUwYkPYgLtDkrhZeQ3CELvL3gachG8j7ZZFakt9Byk/eost19-11.png"],"links":["http://jungle2.cryptolions.io:80","https://monitor.jungletestnet.io/","https://monitor.jungletestnet.io/上点击“faucet”菜单获取。6小时可以获取一次。","http://faucet.cryptokylin.io","http://kylin.fn.eosbixin.com","http://eosfactory.io/build/html/tutorials/05.InteractingWithPublicTestnet.html"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #30536733/Trx 3f3ce0eba5dd0178753794f7e790d2320d7f2921
View Raw JSON Data
{
  "trx_id": "3f3ce0eba5dd0178753794f7e790d2320d7f2921",
  "block": 30536733,
  "trx_in_block": 0,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-02-21T08:25:24",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-testnet",
      "title": "手把手教你玩eos:在公共Testnet上部署和测试智能合约",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![手把手-公众号.jpg](https://cdn.steemitimages.com/DQmS1PzgVtAVWW9ZufURDA7ZVQRehavgU23TWmFzPDJJQTr/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.jpg)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十九篇。本篇教程演示如何使用EOSFactory在公共testnet上部署和测试EOS智能合约,例如Jungle Testnet或CryptoKylin Testnet。\n\n0.2 学习内容\n注册账号\n部署和测试智能合约\n两则技巧\n\n0.3 机器环境\n●笔记本电脑\n●操作系统:Windows 10\n\n1. 注册账号\n1.1 在丛林测试网上注册账号\n我们在eosfactory中注册账号:\ncd /mnt/f/EOS/eosfactory\npython3 utils/register_testnet.py http://jungle2.cryptolions.io:80 myjungle\n![eost19-01.png](https://cdn.steemitimages.com/DQmXJR48uqUW5dEtkuEZBCDDJmvrYj4nULxbvPq4U727bwz/eost19-01.png)\n将对应的账号名和公钥复制下来。\n在浏览器中打开丛林测试网 Jungle Testnet 2.0:\nhttps://monitor.jungletestnet.io/\n点击“Create Account”,在弹出对话框中输入对应账户名和公钥(注意,不是私钥),完成创建。\n![eost19-02.png](https://cdn.steemitimages.com/DQmYNCBVmEuGMDGE2Ld3sbKyLYZ75T3qQPTZubXhD2CcsF4/eost19-02.png)\n完成人机身份验证(注意,如果网络不好的,可能会一直刷不出来)\n然后,点击Create,完成账户注册。\n因为是公共测试网,而不是本地节点,为了方便合约开发。\n我们要通过水龙头,给该账户申请一些EOS,然后抵押资源。\n确保RAM,cpu,net等资源充足。\n在https://monitor.jungletestnet.io/上点击“faucet”菜单获取。6小时可以获取一次。\n![eost19-03.png](https://cdn.steemitimages.com/DQmPzAbpVd98C1JMJZfrRhkLkjVTXiTMfDfeZsoZrUf8qWh/eost19-03.png)\n准备好了,我们再回到命令行,在提示符后面输入 go\n![eost19-04.png](https://cdn.steemitimages.com/DQmS9bP8YRxbA5D3aZGyTzBisLW6koAzHCJra5V26gcJePp/eost19-04.png)\n验证注册完成。\n\n1.2 在麒麟测试网上注册账号\n麒麟测试网上注册要更自动化一些。\n三个参数分别是:对应的水龙头网网址,公共节点网址,账号别名。\n然后,就会自动完成注册和水龙头获取代币。\npython3 utils/register_testnet_via_faucet.py http://faucet.cryptokylin.io http://kylin.fn.eosbixin.com mykylin\n![eost19-05.png](https://cdn.steemitimages.com/DQmbdoxPMduAhJwxNodTSmfVUCvB7LCMLmihsJddkL8jZgn/eost19-05.png)\n\n1.3 查看测试网账号\npython3 utils/testnets.py\n![eost19-06.png](https://cdn.steemitimages.com/DQmQjT7kQvjy39yQ9cM8JtKVsHTUP75LD96en6NjdprUgCN/eost19-06.png)\n\n2. 部署和测试智能合约\n2.1 创建新的智能合约\n目前,还只有 03_tic_tac_toe 模板支持测试网。所以我们基于这个模板创建\npython3 utils/create_project.py foo_bar_net 03_tic_tac_toe --vsc\n![eost19-07.png](https://cdn.steemitimages.com/DQmeCCMb13pqGFCrtNfjt4LY49kxpQWoRmvz3F3nkApd4va/eost19-07.png)\n\n2.2 在丛林测试网上测试\npython3 tests/unittest1.py myjungle\n![eost19-08.png](https://cdn.steemitimages.com/DQmeRaZNWySCwHDF5uWhtVyvzZngomK2fbbRpYbdotXoDAq/eost19-08.png)\npython3 tests/test1.py myjungle\n![eost19-09.png](https://cdn.steemitimages.com/DQmeUDpvVC3LH8jQY1Z8YwSjmuJxoLDBjGgyywU4gp5Y4vX/eost19-09.png)\n\n2.3 在麒麟测试网上测试\npython3 tests/unittest1.py mykylin\n![eost19-10.png](https://cdn.steemitimages.com/DQmXGsiZQQBNcpNvvQgjxjQAfu5pwqjrFhYjFo4ozRwwy8b/eost19-10.png)\npython3 tests/test1.py mykylin\n![eost19-11.png](https://cdn.steemitimages.com/DQmWhRUwYkPYgLtDkrhZeQ3CELvL3gachG8j7ZZFakt9Byk/eost19-11.png)\n\n3 两则技巧\n3.1 清空账号\n测试网中建立的账号在测试时是重复利用的。\n如果您要从头开始运行测试,即把现有帐户从EOSFactory缓存中删除并替换为另一组新创建的帐户,请在命令后面添加该参数: -r\npython3 tests/unittest1.py myjungle -r\n\n3.2 使用自己原来注册好的测试网账号\n如果您在公共测试网上有帐户,则可以跳过使用EOSFactory注册账号,并直接运行单元测试。\n方法是使用-t(或–testnet)选项。\n此选项需要四个参数:\n●提供对testnet的访问的公共节点的URL,例如http://kylin.fn.eosbixin.com,\n●您的帐户名称,在testnet上注册,\n●您帐户的Owner私钥,\n●您帐户的Active私钥。\n命令类似于:\npython3 tests/unittest1.py -t http://kylin.fn.eosbixin.com dgxo1uyhoytn 5JE9XSurh4Bmdw8Ynz72Eh6ZCKrxf63SmQWKrYJSXf1dEnoiKFY 5JgLo7jZhmY4huDNXwExmaWQJqyS1hGZrnSjECcpWwGU25Ym8tA\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n●与公共Testnet交互: http://eosfactory.io/build/html/tutorials/05.InteractingWithPublicTestnet.html\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmS1PzgVtAVWW9ZufURDA7ZVQRehavgU23TWmFzPDJJQTr/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.jpg\",\"https://cdn.steemitimages.com/DQmXJR48uqUW5dEtkuEZBCDDJmvrYj4nULxbvPq4U727bwz/eost19-01.png\",\"https://cdn.steemitimages.com/DQmYNCBVmEuGMDGE2Ld3sbKyLYZ75T3qQPTZubXhD2CcsF4/eost19-02.png\",\"https://cdn.steemitimages.com/DQmPzAbpVd98C1JMJZfrRhkLkjVTXiTMfDfeZsoZrUf8qWh/eost19-03.png\",\"https://cdn.steemitimages.com/DQmS9bP8YRxbA5D3aZGyTzBisLW6koAzHCJra5V26gcJePp/eost19-04.png\",\"https://cdn.steemitimages.com/DQmbdoxPMduAhJwxNodTSmfVUCvB7LCMLmihsJddkL8jZgn/eost19-05.png\",\"https://cdn.steemitimages.com/DQmQjT7kQvjy39yQ9cM8JtKVsHTUP75LD96en6NjdprUgCN/eost19-06.png\",\"https://cdn.steemitimages.com/DQmeCCMb13pqGFCrtNfjt4LY49kxpQWoRmvz3F3nkApd4va/eost19-07.png\",\"https://cdn.steemitimages.com/DQmeRaZNWySCwHDF5uWhtVyvzZngomK2fbbRpYbdotXoDAq/eost19-08.png\",\"https://cdn.steemitimages.com/DQmeUDpvVC3LH8jQY1Z8YwSjmuJxoLDBjGgyywU4gp5Y4vX/eost19-09.png\",\"https://cdn.steemitimages.com/DQmXGsiZQQBNcpNvvQgjxjQAfu5pwqjrFhYjFo4ozRwwy8b/eost19-10.png\",\"https://cdn.steemitimages.com/DQmWhRUwYkPYgLtDkrhZeQ3CELvL3gachG8j7ZZFakt9Byk/eost19-11.png\"],\"links\":[\"http://jungle2.cryptolions.io:80\",\"https://monitor.jungletestnet.io/\",\"https://monitor.jungletestnet.io/上点击“faucet”菜单获取。6小时可以获取一次。\",\"http://faucet.cryptokylin.io\",\"http://kylin.fn.eosbixin.com\",\"http://eosfactory.io/build/html/tutorials/05.InteractingWithPublicTestnet.html\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2019/02/13 08:02:30
votermerlin7
authoreoswing
permlinkeos-visual-studio-code-eosfactory
weight1 (0.01%)
Transaction InfoBlock #30306049/Trx be3208e93bc5f8d0dcfe82717af432922b3823c2
View Raw JSON Data
{
  "trx_id": "be3208e93bc5f8d0dcfe82717af432922b3823c2",
  "block": 30306049,
  "trx_in_block": 1,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-02-13T08:02:30",
  "op": [
    "vote",
    {
      "voter": "merlin7",
      "author": "eoswing",
      "permlink": "eos-visual-studio-code-eosfactory",
      "weight": 1
    }
  ]
}
2019/02/13 08:01:36
parent authoreoswing
parent permlinkeos-visual-studio-code-eosfactory
authorintroduce.bot
permlinkintroduce-bot-re-eoswingeos-visual-studio-code-eosfactory
title
body✅ Enjoy the vote! For more amazing content, please follow @themadcurator for a chance to receive more free votes!
json metadata
Transaction InfoBlock #30306031/Trx 8d00f2ac6167229444b006172ea9214f209e67aa
View Raw JSON Data
{
  "trx_id": "8d00f2ac6167229444b006172ea9214f209e67aa",
  "block": 30306031,
  "trx_in_block": 4,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-02-13T08:01:36",
  "op": [
    "comment",
    {
      "parent_author": "eoswing",
      "parent_permlink": "eos-visual-studio-code-eosfactory",
      "author": "introduce.bot",
      "permlink": "introduce-bot-re-eoswingeos-visual-studio-code-eosfactory",
      "title": "",
      "body": "✅ Enjoy the vote! For more amazing content, please follow @themadcurator for a chance to receive more free votes!",
      "json_metadata": ""
    }
  ]
}
2019/02/13 08:01:33
voterintroduce.bot
authoreoswing
permlinkeos-visual-studio-code-eosfactory
weight100 (1.00%)
Transaction InfoBlock #30306030/Trx a6fa042b335e9db9379850df39820ece205a9f5f
View Raw JSON Data
{
  "trx_id": "a6fa042b335e9db9379850df39820ece205a9f5f",
  "block": 30306030,
  "trx_in_block": 19,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-02-13T08:01:33",
  "op": [
    "vote",
    {
      "voter": "introduce.bot",
      "author": "eoswing",
      "permlink": "eos-visual-studio-code-eosfactory",
      "weight": 100
    }
  ]
}
2019/02/13 07:46:24
parent author
parent permlinkeos
authoreoswing
permlinkeos-visual-studio-code-eosfactory
title手把手教你玩eos:Visual Studio Code和EOSFactory的结合使用
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![手把手-公众号.png](https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十八篇。本篇教程讲解如何将EOSFactory与Visual Studio Code结合使用,以简化使用EOS智能合约的过程。 0.2 学习内容 1.安装和配置Visual Studio Code 2.在VSCode中开发智能合约项目 3.在VSCode中优化工作 0.3 机器环境 ●笔记本电脑 ●操作系统:Windows 10 1.安装和配置Visual Studio Code 1.1 关于VSCode 在前面的教程里,我们大部分时间使用vi来编辑代码,但是对于大部分初学者来说,这是很不方便的。 在这里我们将配置vscode作为我们开发eos智能合约用IDE。 Visual Studio Code (简称 VSCode) 是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段、代码对比 Diff、GIT命令 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。软件运行流畅,功能强大。 1.2 在官网下载VSCode 进入官网:https://code.visualstudio.com/Download,选择Windows版本的安装包下载。 ![eost18-01.png](https://cdn.steemitimages.com/DQmYBxn7c64xfWrNgLMLnnPGM1bWRZudXuq5sTsGj2ayozR/eost18-01.png) 安装过程比较简单,不再赘述。 1.3 安装C/C++ 插件 EOS是用c++开发的,所以打开vscode之后先安装c++插件 ![eost18-02.png](https://cdn.steemitimages.com/DQmVpwf3DAruY13CiFKs8UCr7nyCNW2eLynFtJBik6JDq8e/eost18-02.png) 点击右侧最下方图标,在出现的插件列表里,选择C/C++ 插件。点击Install安装。 我这里已经安装好插件了,所以是一个设置图标。 1.4 配置命令行调用 首先打开设置面板。File -> Preferences -> Settings ![eost18-03.png](https://cdn.steemitimages.com/DQmcp4RF3DKCkpRw3PR2BG2pD3UKQe3GKxXNfYEnVjnWmNu/eost18-03.png) 然后,在Features -> terminal -> integrated>shell:windows 选项中配置参数为: C:\Windows\sysnative\bash.exe ![eost18-04.png](https://cdn.steemitimages.com/DQmRsMzzi9J6EmAUNKwDZcSGT66AsUvwJWHgGUSsS9Trz8n/eost18-04.png) 关闭设置面板。选择View -> Terminal ,在下方打开命令行面板。 ![eost18-05.png](https://cdn.steemitimages.com/DQmSmTpzbQPaPVTZntjyTfcF4xxjp2hDHqb4Wx1smaJph4P/eost18-05.png) 2 在VSCode中开发智能合约项目 2.1 创建一个新的智能合约项目 在bash终端中,进入eosfactory文件夹,创建一个新的智能合约。 cd /mnt/f/EOS/eosfactory python3 utils/create_project.py foo_bar_vsc 01_hello_world --vsc ![eost18-06.png](https://cdn.steemitimages.com/DQmdnPuXiSsHnigXsmpLEy3CfzBhdTEKR9Ryo353ZiFQkrx/eost18-06.png) 第一个参数(foo_bar_vsc)是您的合同的名称。它可以是您想要的任何名称,前提是它没有空格。允许使用字母,数字,下划线_,点.和破折号-。 第二个参数(01_hello_world)表示将从中创建新合同的模板。截至目前已经有三个模板可供选择(即01_hello_world,02_eosio_token和03_tic_tac_toe)。此参数是可选的,默认值为01_hello_world。 第三个参数(–vsc)是将项目在VSCode中打开。会启动一个新的VSCode界面,并切换到项目文件夹。 ![eost18-07.png](https://cdn.steemitimages.com/DQmPTj2DQPaUJJgZ5s4JiTcBwEB7GugWX3qmcKWGFuqSnrK/eost18-07.png) 2.2 项目结构 点开查看下完整的项目结构。 ![eost18-08.png](https://cdn.steemitimages.com/DQmUpVHHFMG6Yao6C7yFpff3bHM8qrkPtQUriR2HZqZGK72/eost18-08.png) 在foo_bar_vsc项目文件夹里,智能合约源代码,构建输出文件和单元测试分布在不同文件夹里。 ●.vscode目录。 包含IntelliSense定义,任务定义等。 ●build目录。 编译后生成文件。 ●resources目录。 资源文件,比如Ricardian等合同文件。 ●src目录。 源文件,cpp和hpp。 ●tests目录。 测试文件。 ●CMakeLists.txt CMake定义文件。 我们打开主要的源文件foo_bar_vsc.cpp查看下: ![eost18-09.png](https://cdn.steemitimages.com/DQmbXCXWM5fzKgSu6595QDHRxAkaE6etKeC9x4KF5xuyBWs/eost18-09.png) vscode中,编辑代码很智能也很方便。 2.3 构建智能合约 我们使用cmake和make来构建智能合约。 首先选择View -> Integrated Terminal,在下方打开命令行。 先cmake构建一下: cd bulid cmake .. ![eost18-10.png](https://cdn.steemitimages.com/DQmPuVyqH6RswbZP6MjN5sA1QshigmPFUxRtRhSkGuiRpzH/eost18-10.png) 等待完成后,再make编译。 make ![eost18-11.png](https://cdn.steemitimages.com/DQmcuBWYspP5gFeZJPN3g1M76GAikLYKSXGueHiV9JWWhb7/eost18-11.png) 这样,我们就在build文件夹里编译好了foo_bar_src.abi和foo_bar_src.wasm两个文件。 2.4 单元测试 编译好文件后,我们开始单元测试。 输入命令行。 ctest ![eost18-12.png](https://cdn.steemitimages.com/DQmQK1HCr33L2KbADnXqjbHE1tgWHw6vhh9R4c5PJeQGtf1/eost18-12.png) 如果要使单元测试更详细,请加上-V参数: ctest -V 注意: 您可能已经注意到,有两种类型的单元测试:标准测试(命名为unittest1,unittest2等)和ad-hoc测试(命名为test1,test2等)。 这种二元性的原因在于:我们发现使用标准单元测试来证明事情按预期工作是有用的,并且通过临时测试来调查错误并且通常监视智能合约的内部工作。 EOSFactory支持两者,因此您可以选择任何适合您需求的产品。 当然,我们也可以直接用Python调用测试文件进行测试。 cd .. python3 tests/test1.py python3 tests/unittest1.py ![eost18-13.png](https://cdn.steemitimages.com/DQmc6NGHn5YBm8AN3G1q3aSYu7XLHF1YRjMtrcmTsoqBTjA/eost18-13.png) 3 在VSCode中优化工作 在菜单栏选择 Terminal > Run Task。 ![eost18-14.png](https://cdn.steemitimages.com/DQmbTC7KdMgriQPJPDCYk9ZQDkcwvsLGbrv781SrnEr5otw/eost18-14.png) 稍等片刻,你会看到下拉菜单有五个选项提示: ![eost18-15.png](https://cdn.steemitimages.com/DQmYdBkfPYCDniYRqDpAXcUL3AwED7jghwBv76RTAUfxe57/eost18-15.png) 分别是: ●Build 完整构建合约,在build文件夹生成ABI和WAST文件。 ●Compile 快速完成合约编译,注意,不会构建合约(既不生成ABI也不生成WAST)。如果编译中代码有错,会列出了代码错误。 ●EOSIO API 打开EOSIO文档。 ●Test 执行test1.py脚本。 ●Unittest 执行unittest1.py脚本。 我们先将build文件夹下面的所有文件删除,然后挨个测试下这些命令。 在这里有一个小的环境设置问题。 要将.vscode中的tasks.json中的bash.exe都替换为C:\Windows\sysnative\bash.exe 共有5处,都要修改。 ![eost18-16.png](https://cdn.steemitimages.com/DQmYwyvZSFDms4sR4WNbUAX8vTjc2rZj1UQygTGqZffyn7b/eost18-16.png) 3.1 编译 Terminal > Run Task > Compile ![eost18-17.png](https://cdn.steemitimages.com/DQmavXZZNhC3kgDyKsWd2vz5TzpFRzq8MgEVRzmJAKJrdsB/eost18-17.png) 代码编译通过,没有报错。 将print 修改为 myprint 再次运行编译,会发现报错。 ![eost18-18.png](https://cdn.steemitimages.com/DQmdXZR8hLCmfT6QvEzoGbAc5UX9g2tq9r5AY3uyr6uf4j8/eost18-18.png) 再修改会print 3.2 构建 将整个build文件夹删除,我们再看看构建的效果。 Terminal > Run Task > Build ![eost18-19.png](https://cdn.steemitimages.com/DQmQpZNSHbDvmaPzfkqrRzj25hPx5NmRcJkHuv8aC6K5GZs/eost18-19.png) 我们看到,自动新建了build文件夹,并生成了abi和wasm文件。 3.3 测试 Terminal > Run Task > Test ![eost18-20.png](https://cdn.steemitimages.com/DQmQy6x7ismeHVpiD5mpqoH3SP8j6E4AsFp56uzwoi4akHW/eost18-20.png) 3.4 单元测试 Terminal > Run Task > Unittest ![eost18-21.png](https://cdn.steemitimages.com/DQmbagjo9YDj2xSAQbMBTA8c5VXUTTkzH7adVk4vTYC9ee6/eost18-21.png) 3.5 绑定快捷键 我们还可以将这些task绑定成快捷键,来进一步优化工作。 File -> Preferences -> Keyboard Shortcuts 选择编辑 keybindings.json 文件 ![eost18-22.png](https://cdn.steemitimages.com/DQmaRKEU2Cg6CScfN54ZfL6K7N7uSVEjPcoiAWhxhQnEHWy/eost18-22.png) 输入类似如下配置文件: { "key": "ctrl+shift+c", "command": "workbench.action.tasks.runTask", "args": "Compile" } { "key": "ctrl+shift+t", "command": "workbench.action.tasks.runTask", "args": "Test" } { "key": "ctrl+shift+u", "command": "workbench.action.tasks.runTask", "args": "Unittest" } ![eost18-23.png](https://cdn.steemitimages.com/DQmZ7pQwfawLnFuXCQatqk1S815N5zkU2RRzP5FEv2wJ2iJ/eost18-23.png) 然后保存退出。这样我们就为Compile,Test 和 Unittest 都绑定了对应的快捷键。 可以在开发环境中测试下,直接输入快捷键的调用情况。 3.6 智能提示 点击左侧的扩展快捷,在输入框中输入 C++ IntelliSense 安装C++ IntelliSense插件。 ![eost18-24.png](https://cdn.steemitimages.com/DQmXUMKxckGEg1MwtQg9edFqPAZ3xV9fbXyNJrEVSmkHQSn/eost18-24.png) 安装完成后,鼠标移动到对应函数方法,可以看到函数方法提示。 ![eost18-25.png](https://cdn.steemitimages.com/DQmQo4t1EcyYrNsgDGb44Yf9FGebbzni76xfG1jtRaAyhNe/eost18-25.png) 3.7 使用智能合约logger调试 使用智能合约logger实际上是调试智能合约的唯一方法。 比如,在源文件foo_bar_vsc.cpp第15行,就是使用智能合约logger。 logger_info( "debug user name: ", name{user} ); 我们按快捷键ctrl+shift+t。可以在测试中,看到对应的调试信息。 ![eost18-26.png](https://cdn.steemitimages.com/DQmVLicjRoYsZr4vg5RYqifL6w3R8tKxHULnzJUQksa3NtA/eost18-26.png) 在示例合约 02_eosio_token 模板中也有类似的调试查看代币数的logger语句: logger_info("quantity.amount: ", quantity.amount); 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: ●使用EOSFactory构建和部署智能合约: http://eosfactory.io/build/html/tutorials/04.WorkingWithEOSContractsUsingEOSFactoryInVSC.html 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png","https://cdn.steemitimages.com/DQmYBxn7c64xfWrNgLMLnnPGM1bWRZudXuq5sTsGj2ayozR/eost18-01.png","https://cdn.steemitimages.com/DQmVpwf3DAruY13CiFKs8UCr7nyCNW2eLynFtJBik6JDq8e/eost18-02.png","https://cdn.steemitimages.com/DQmcp4RF3DKCkpRw3PR2BG2pD3UKQe3GKxXNfYEnVjnWmNu/eost18-03.png","https://cdn.steemitimages.com/DQmRsMzzi9J6EmAUNKwDZcSGT66AsUvwJWHgGUSsS9Trz8n/eost18-04.png","https://cdn.steemitimages.com/DQmSmTpzbQPaPVTZntjyTfcF4xxjp2hDHqb4Wx1smaJph4P/eost18-05.png","https://cdn.steemitimages.com/DQmdnPuXiSsHnigXsmpLEy3CfzBhdTEKR9Ryo353ZiFQkrx/eost18-06.png","https://cdn.steemitimages.com/DQmPTj2DQPaUJJgZ5s4JiTcBwEB7GugWX3qmcKWGFuqSnrK/eost18-07.png","https://cdn.steemitimages.com/DQmUpVHHFMG6Yao6C7yFpff3bHM8qrkPtQUriR2HZqZGK72/eost18-08.png","https://cdn.steemitimages.com/DQmbXCXWM5fzKgSu6595QDHRxAkaE6etKeC9x4KF5xuyBWs/eost18-09.png","https://cdn.steemitimages.com/DQmPuVyqH6RswbZP6MjN5sA1QshigmPFUxRtRhSkGuiRpzH/eost18-10.png","https://cdn.steemitimages.com/DQmcuBWYspP5gFeZJPN3g1M76GAikLYKSXGueHiV9JWWhb7/eost18-11.png","https://cdn.steemitimages.com/DQmQK1HCr33L2KbADnXqjbHE1tgWHw6vhh9R4c5PJeQGtf1/eost18-12.png","https://cdn.steemitimages.com/DQmc6NGHn5YBm8AN3G1q3aSYu7XLHF1YRjMtrcmTsoqBTjA/eost18-13.png","https://cdn.steemitimages.com/DQmbTC7KdMgriQPJPDCYk9ZQDkcwvsLGbrv781SrnEr5otw/eost18-14.png","https://cdn.steemitimages.com/DQmYdBkfPYCDniYRqDpAXcUL3AwED7jghwBv76RTAUfxe57/eost18-15.png","https://cdn.steemitimages.com/DQmYwyvZSFDms4sR4WNbUAX8vTjc2rZj1UQygTGqZffyn7b/eost18-16.png","https://cdn.steemitimages.com/DQmavXZZNhC3kgDyKsWd2vz5TzpFRzq8MgEVRzmJAKJrdsB/eost18-17.png","https://cdn.steemitimages.com/DQmdXZR8hLCmfT6QvEzoGbAc5UX9g2tq9r5AY3uyr6uf4j8/eost18-18.png","https://cdn.steemitimages.com/DQmQpZNSHbDvmaPzfkqrRzj25hPx5NmRcJkHuv8aC6K5GZs/eost18-19.png","https://cdn.steemitimages.com/DQmQy6x7ismeHVpiD5mpqoH3SP8j6E4AsFp56uzwoi4akHW/eost18-20.png","https://cdn.steemitimages.com/DQmbagjo9YDj2xSAQbMBTA8c5VXUTTkzH7adVk4vTYC9ee6/eost18-21.png","https://cdn.steemitimages.com/DQmaRKEU2Cg6CScfN54ZfL6K7N7uSVEjPcoiAWhxhQnEHWy/eost18-22.png","https://cdn.steemitimages.com/DQmZ7pQwfawLnFuXCQatqk1S815N5zkU2RRzP5FEv2wJ2iJ/eost18-23.png","https://cdn.steemitimages.com/DQmXUMKxckGEg1MwtQg9edFqPAZ3xV9fbXyNJrEVSmkHQSn/eost18-24.png","https://cdn.steemitimages.com/DQmQo4t1EcyYrNsgDGb44Yf9FGebbzni76xfG1jtRaAyhNe/eost18-25.png","https://cdn.steemitimages.com/DQmVLicjRoYsZr4vg5RYqifL6w3R8tKxHULnzJUQksa3NtA/eost18-26.png"],"links":["https://code.visualstudio.com/Download,选择Windows版本的安装包下载。","http://eosfactory.io/build/html/tutorials/04.WorkingWithEOSContractsUsingEOSFactoryInVSC.html"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #30305727/Trx 2b9ee1c7483cb4682d276c5eedccfe47a0add83f
View Raw JSON Data
{
  "trx_id": "2b9ee1c7483cb4682d276c5eedccfe47a0add83f",
  "block": 30305727,
  "trx_in_block": 7,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-02-13T07:46:24",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-visual-studio-code-eosfactory",
      "title": "手把手教你玩eos:Visual Studio Code和EOSFactory的结合使用",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![手把手-公众号.png](https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十八篇。本篇教程讲解如何将EOSFactory与Visual Studio Code结合使用,以简化使用EOS智能合约的过程。\n\n0.2 学习内容\n1.安装和配置Visual Studio Code\n2.在VSCode中开发智能合约项目\n3.在VSCode中优化工作\n\n0.3 机器环境\n●笔记本电脑\n●操作系统:Windows 10\n\n1.安装和配置Visual Studio Code\n1.1 关于VSCode\n在前面的教程里,我们大部分时间使用vi来编辑代码,但是对于大部分初学者来说,这是很不方便的。\n在这里我们将配置vscode作为我们开发eos智能合约用IDE。\nVisual Studio Code (简称 VSCode) 是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段、代码对比 Diff、GIT命令 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。软件运行流畅,功能强大。\n\n1.2 在官网下载VSCode\n进入官网:https://code.visualstudio.com/Download,选择Windows版本的安装包下载。\n![eost18-01.png](https://cdn.steemitimages.com/DQmYBxn7c64xfWrNgLMLnnPGM1bWRZudXuq5sTsGj2ayozR/eost18-01.png)\n安装过程比较简单,不再赘述。\n\n1.3 安装C/C++ 插件\nEOS是用c++开发的,所以打开vscode之后先安装c++插件\n![eost18-02.png](https://cdn.steemitimages.com/DQmVpwf3DAruY13CiFKs8UCr7nyCNW2eLynFtJBik6JDq8e/eost18-02.png)\n点击右侧最下方图标,在出现的插件列表里,选择C/C++ 插件。点击Install安装。\n我这里已经安装好插件了,所以是一个设置图标。\n\n1.4 配置命令行调用\n首先打开设置面板。File -> Preferences -> Settings\n![eost18-03.png](https://cdn.steemitimages.com/DQmcp4RF3DKCkpRw3PR2BG2pD3UKQe3GKxXNfYEnVjnWmNu/eost18-03.png)\n然后,在Features -> terminal -> integrated>shell:windows 选项中配置参数为:\nC:\\Windows\\sysnative\\bash.exe\n![eost18-04.png](https://cdn.steemitimages.com/DQmRsMzzi9J6EmAUNKwDZcSGT66AsUvwJWHgGUSsS9Trz8n/eost18-04.png)\n关闭设置面板。选择View -> Terminal ,在下方打开命令行面板。\n![eost18-05.png](https://cdn.steemitimages.com/DQmSmTpzbQPaPVTZntjyTfcF4xxjp2hDHqb4Wx1smaJph4P/eost18-05.png)\n\n2 在VSCode中开发智能合约项目\n2.1 创建一个新的智能合约项目\n在bash终端中,进入eosfactory文件夹,创建一个新的智能合约。\ncd /mnt/f/EOS/eosfactory\npython3 utils/create_project.py foo_bar_vsc 01_hello_world --vsc\n![eost18-06.png](https://cdn.steemitimages.com/DQmdnPuXiSsHnigXsmpLEy3CfzBhdTEKR9Ryo353ZiFQkrx/eost18-06.png)\n第一个参数(foo_bar_vsc)是您的合同的名称。它可以是您想要的任何名称,前提是它没有空格。允许使用字母,数字,下划线_,点.和破折号-。\n第二个参数(01_hello_world)表示将从中创建新合同的模板。截至目前已经有三个模板可供选择(即01_hello_world,02_eosio_token和03_tic_tac_toe)。此参数是可选的,默认值为01_hello_world。\n第三个参数(–vsc)是将项目在VSCode中打开。会启动一个新的VSCode界面,并切换到项目文件夹。\n![eost18-07.png](https://cdn.steemitimages.com/DQmPTj2DQPaUJJgZ5s4JiTcBwEB7GugWX3qmcKWGFuqSnrK/eost18-07.png)\n\n2.2 项目结构\n点开查看下完整的项目结构。\n![eost18-08.png](https://cdn.steemitimages.com/DQmUpVHHFMG6Yao6C7yFpff3bHM8qrkPtQUriR2HZqZGK72/eost18-08.png)\n在foo_bar_vsc项目文件夹里,智能合约源代码,构建输出文件和单元测试分布在不同文件夹里。\n●.vscode目录。 包含IntelliSense定义,任务定义等。\n●build目录。 编译后生成文件。\n●resources目录。 资源文件,比如Ricardian等合同文件。\n●src目录。 源文件,cpp和hpp。\n●tests目录。 测试文件。\n●CMakeLists.txt CMake定义文件。\n我们打开主要的源文件foo_bar_vsc.cpp查看下:\n![eost18-09.png](https://cdn.steemitimages.com/DQmbXCXWM5fzKgSu6595QDHRxAkaE6etKeC9x4KF5xuyBWs/eost18-09.png)\nvscode中,编辑代码很智能也很方便。\n\n2.3 构建智能合约\n我们使用cmake和make来构建智能合约。\n首先选择View -> Integrated Terminal,在下方打开命令行。\n先cmake构建一下:\ncd bulid\ncmake ..\n![eost18-10.png](https://cdn.steemitimages.com/DQmPuVyqH6RswbZP6MjN5sA1QshigmPFUxRtRhSkGuiRpzH/eost18-10.png)\n等待完成后,再make编译。\n\nmake\n![eost18-11.png](https://cdn.steemitimages.com/DQmcuBWYspP5gFeZJPN3g1M76GAikLYKSXGueHiV9JWWhb7/eost18-11.png)\n这样,我们就在build文件夹里编译好了foo_bar_src.abi和foo_bar_src.wasm两个文件。\n\n2.4 单元测试\n编译好文件后,我们开始单元测试。\n输入命令行。\nctest\n![eost18-12.png](https://cdn.steemitimages.com/DQmQK1HCr33L2KbADnXqjbHE1tgWHw6vhh9R4c5PJeQGtf1/eost18-12.png)\n如果要使单元测试更详细,请加上-V参数: ctest -V\n注意: 您可能已经注意到,有两种类型的单元测试:标准测试(命名为unittest1,unittest2等)和ad-hoc测试(命名为test1,test2等)。\n这种二元性的原因在于:我们发现使用标准单元测试来证明事情按预期工作是有用的,并且通过临时测试来调查错误并且通常监视智能合约的内部工作。\nEOSFactory支持两者,因此您可以选择任何适合您需求的产品。\n当然,我们也可以直接用Python调用测试文件进行测试。\n\ncd ..\npython3 tests/test1.py\npython3 tests/unittest1.py\n![eost18-13.png](https://cdn.steemitimages.com/DQmc6NGHn5YBm8AN3G1q3aSYu7XLHF1YRjMtrcmTsoqBTjA/eost18-13.png)\n\n3 在VSCode中优化工作\n在菜单栏选择 Terminal > Run Task。\n![eost18-14.png](https://cdn.steemitimages.com/DQmbTC7KdMgriQPJPDCYk9ZQDkcwvsLGbrv781SrnEr5otw/eost18-14.png)\n稍等片刻,你会看到下拉菜单有五个选项提示:\n![eost18-15.png](https://cdn.steemitimages.com/DQmYdBkfPYCDniYRqDpAXcUL3AwED7jghwBv76RTAUfxe57/eost18-15.png)\n分别是:\n●Build 完整构建合约,在build文件夹生成ABI和WAST文件。\n●Compile 快速完成合约编译,注意,不会构建合约(既不生成ABI也不生成WAST)。如果编译中代码有错,会列出了代码错误。\n●EOSIO API 打开EOSIO文档。\n●Test 执行test1.py脚本。\n●Unittest 执行unittest1.py脚本。\n我们先将build文件夹下面的所有文件删除,然后挨个测试下这些命令。\n在这里有一个小的环境设置问题。\n要将.vscode中的tasks.json中的bash.exe都替换为C:\\Windows\\sysnative\\bash.exe\n共有5处,都要修改。\n![eost18-16.png](https://cdn.steemitimages.com/DQmYwyvZSFDms4sR4WNbUAX8vTjc2rZj1UQygTGqZffyn7b/eost18-16.png)\n\n3.1 编译\nTerminal > Run Task > Compile\n![eost18-17.png](https://cdn.steemitimages.com/DQmavXZZNhC3kgDyKsWd2vz5TzpFRzq8MgEVRzmJAKJrdsB/eost18-17.png)\n代码编译通过,没有报错。\n将print 修改为 myprint\n再次运行编译,会发现报错。\n![eost18-18.png](https://cdn.steemitimages.com/DQmdXZR8hLCmfT6QvEzoGbAc5UX9g2tq9r5AY3uyr6uf4j8/eost18-18.png)\n再修改会print\n\n3.2 构建\n将整个build文件夹删除,我们再看看构建的效果。\nTerminal > Run Task > Build\n![eost18-19.png](https://cdn.steemitimages.com/DQmQpZNSHbDvmaPzfkqrRzj25hPx5NmRcJkHuv8aC6K5GZs/eost18-19.png)\n我们看到,自动新建了build文件夹,并生成了abi和wasm文件。\n\n3.3 测试\nTerminal > Run Task > Test\n![eost18-20.png](https://cdn.steemitimages.com/DQmQy6x7ismeHVpiD5mpqoH3SP8j6E4AsFp56uzwoi4akHW/eost18-20.png)\n\n3.4 单元测试\nTerminal > Run Task > Unittest\n![eost18-21.png](https://cdn.steemitimages.com/DQmbagjo9YDj2xSAQbMBTA8c5VXUTTkzH7adVk4vTYC9ee6/eost18-21.png)\n\n3.5 绑定快捷键\n我们还可以将这些task绑定成快捷键,来进一步优化工作。\nFile -> Preferences -> Keyboard Shortcuts\n选择编辑 keybindings.json 文件\n![eost18-22.png](https://cdn.steemitimages.com/DQmaRKEU2Cg6CScfN54ZfL6K7N7uSVEjPcoiAWhxhQnEHWy/eost18-22.png)\n输入类似如下配置文件:\n{\n       \"key\": \"ctrl+shift+c\",\n       \"command\": \"workbench.action.tasks.runTask\",\n       \"args\": \"Compile\"\n   }\n   {\n       \"key\": \"ctrl+shift+t\",\n       \"command\": \"workbench.action.tasks.runTask\",\n       \"args\": \"Test\"\n   }\n   {\n       \"key\": \"ctrl+shift+u\",\n       \"command\": \"workbench.action.tasks.runTask\",\n       \"args\": \"Unittest\"\n   }\n![eost18-23.png](https://cdn.steemitimages.com/DQmZ7pQwfawLnFuXCQatqk1S815N5zkU2RRzP5FEv2wJ2iJ/eost18-23.png)\n然后保存退出。这样我们就为Compile,Test 和 Unittest 都绑定了对应的快捷键。\n可以在开发环境中测试下,直接输入快捷键的调用情况。\n\n3.6 智能提示\n点击左侧的扩展快捷,在输入框中输入 C++ IntelliSense\n安装C++ IntelliSense插件。\n![eost18-24.png](https://cdn.steemitimages.com/DQmXUMKxckGEg1MwtQg9edFqPAZ3xV9fbXyNJrEVSmkHQSn/eost18-24.png)\n安装完成后,鼠标移动到对应函数方法,可以看到函数方法提示。\n![eost18-25.png](https://cdn.steemitimages.com/DQmQo4t1EcyYrNsgDGb44Yf9FGebbzni76xfG1jtRaAyhNe/eost18-25.png)\n\n3.7 使用智能合约logger调试\n使用智能合约logger实际上是调试智能合约的唯一方法。\n比如,在源文件foo_bar_vsc.cpp第15行,就是使用智能合约logger。\nlogger_info( \"debug user name: \", name{user} );\n我们按快捷键ctrl+shift+t。可以在测试中,看到对应的调试信息。\n![eost18-26.png](https://cdn.steemitimages.com/DQmVLicjRoYsZr4vg5RYqifL6w3R8tKxHULnzJUQksa3NtA/eost18-26.png)\n在示例合约 02_eosio_token 模板中也有类似的调试查看代币数的logger语句:\nlogger_info(\"quantity.amount: \", quantity.amount);\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n●使用EOSFactory构建和部署智能合约: http://eosfactory.io/build/html/tutorials/04.WorkingWithEOSContractsUsingEOSFactoryInVSC.html\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png\",\"https://cdn.steemitimages.com/DQmYBxn7c64xfWrNgLMLnnPGM1bWRZudXuq5sTsGj2ayozR/eost18-01.png\",\"https://cdn.steemitimages.com/DQmVpwf3DAruY13CiFKs8UCr7nyCNW2eLynFtJBik6JDq8e/eost18-02.png\",\"https://cdn.steemitimages.com/DQmcp4RF3DKCkpRw3PR2BG2pD3UKQe3GKxXNfYEnVjnWmNu/eost18-03.png\",\"https://cdn.steemitimages.com/DQmRsMzzi9J6EmAUNKwDZcSGT66AsUvwJWHgGUSsS9Trz8n/eost18-04.png\",\"https://cdn.steemitimages.com/DQmSmTpzbQPaPVTZntjyTfcF4xxjp2hDHqb4Wx1smaJph4P/eost18-05.png\",\"https://cdn.steemitimages.com/DQmdnPuXiSsHnigXsmpLEy3CfzBhdTEKR9Ryo353ZiFQkrx/eost18-06.png\",\"https://cdn.steemitimages.com/DQmPTj2DQPaUJJgZ5s4JiTcBwEB7GugWX3qmcKWGFuqSnrK/eost18-07.png\",\"https://cdn.steemitimages.com/DQmUpVHHFMG6Yao6C7yFpff3bHM8qrkPtQUriR2HZqZGK72/eost18-08.png\",\"https://cdn.steemitimages.com/DQmbXCXWM5fzKgSu6595QDHRxAkaE6etKeC9x4KF5xuyBWs/eost18-09.png\",\"https://cdn.steemitimages.com/DQmPuVyqH6RswbZP6MjN5sA1QshigmPFUxRtRhSkGuiRpzH/eost18-10.png\",\"https://cdn.steemitimages.com/DQmcuBWYspP5gFeZJPN3g1M76GAikLYKSXGueHiV9JWWhb7/eost18-11.png\",\"https://cdn.steemitimages.com/DQmQK1HCr33L2KbADnXqjbHE1tgWHw6vhh9R4c5PJeQGtf1/eost18-12.png\",\"https://cdn.steemitimages.com/DQmc6NGHn5YBm8AN3G1q3aSYu7XLHF1YRjMtrcmTsoqBTjA/eost18-13.png\",\"https://cdn.steemitimages.com/DQmbTC7KdMgriQPJPDCYk9ZQDkcwvsLGbrv781SrnEr5otw/eost18-14.png\",\"https://cdn.steemitimages.com/DQmYdBkfPYCDniYRqDpAXcUL3AwED7jghwBv76RTAUfxe57/eost18-15.png\",\"https://cdn.steemitimages.com/DQmYwyvZSFDms4sR4WNbUAX8vTjc2rZj1UQygTGqZffyn7b/eost18-16.png\",\"https://cdn.steemitimages.com/DQmavXZZNhC3kgDyKsWd2vz5TzpFRzq8MgEVRzmJAKJrdsB/eost18-17.png\",\"https://cdn.steemitimages.com/DQmdXZR8hLCmfT6QvEzoGbAc5UX9g2tq9r5AY3uyr6uf4j8/eost18-18.png\",\"https://cdn.steemitimages.com/DQmQpZNSHbDvmaPzfkqrRzj25hPx5NmRcJkHuv8aC6K5GZs/eost18-19.png\",\"https://cdn.steemitimages.com/DQmQy6x7ismeHVpiD5mpqoH3SP8j6E4AsFp56uzwoi4akHW/eost18-20.png\",\"https://cdn.steemitimages.com/DQmbagjo9YDj2xSAQbMBTA8c5VXUTTkzH7adVk4vTYC9ee6/eost18-21.png\",\"https://cdn.steemitimages.com/DQmaRKEU2Cg6CScfN54ZfL6K7N7uSVEjPcoiAWhxhQnEHWy/eost18-22.png\",\"https://cdn.steemitimages.com/DQmZ7pQwfawLnFuXCQatqk1S815N5zkU2RRzP5FEv2wJ2iJ/eost18-23.png\",\"https://cdn.steemitimages.com/DQmXUMKxckGEg1MwtQg9edFqPAZ3xV9fbXyNJrEVSmkHQSn/eost18-24.png\",\"https://cdn.steemitimages.com/DQmQo4t1EcyYrNsgDGb44Yf9FGebbzni76xfG1jtRaAyhNe/eost18-25.png\",\"https://cdn.steemitimages.com/DQmVLicjRoYsZr4vg5RYqifL6w3R8tKxHULnzJUQksa3NtA/eost18-26.png\"],\"links\":[\"https://code.visualstudio.com/Download,选择Windows版本的安装包下载。\",\"http://eosfactory.io/build/html/tutorials/04.WorkingWithEOSContractsUsingEOSFactoryInVSC.html\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2019/01/30 16:00:33
parent authoreoswing
parent permlinkeos-eosfactory
authorsteemitboard
permlinksteemitboard-notify-eoswing-20190130t160035000z
title
bodyCongratulations @eoswing! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) : <table><tr><td>https://steemitimages.com/60x70/http://steemitboard.com/@eoswing/posts.png?201901300923</td><td>You published more than 20 posts. Your next target is to reach 30 posts.</td></tr> </table> <sub>_[Click here to view your Board](https://steemitboard.com/@eoswing)_</sub> <sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub> > Support [SteemitBoard's project](https://steemit.com/@steemitboard)! **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!
json metadata{"image":["https://steemitboard.com/img/notify.png"]}
Transaction InfoBlock #29912745/Trx cda683dd8522536dbb85c5c6da4beb2aced8fc9c
View Raw JSON Data
{
  "trx_id": "cda683dd8522536dbb85c5c6da4beb2aced8fc9c",
  "block": 29912745,
  "trx_in_block": 38,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-30T16:00:33",
  "op": [
    "comment",
    {
      "parent_author": "eoswing",
      "parent_permlink": "eos-eosfactory",
      "author": "steemitboard",
      "permlink": "steemitboard-notify-eoswing-20190130t160035000z",
      "title": "",
      "body": "Congratulations @eoswing! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :\n\n<table><tr><td>https://steemitimages.com/60x70/http://steemitboard.com/@eoswing/posts.png?201901300923</td><td>You published more than 20 posts. Your next target is to reach 30 posts.</td></tr>\n</table>\n\n<sub>_[Click here to view your Board](https://steemitboard.com/@eoswing)_</sub>\n<sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub>\n\n\n\n> Support [SteemitBoard's project](https://steemit.com/@steemitboard)! **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!",
      "json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}"
    }
  ]
}
eoswingpublished a new post: eos-eosfactory
2019/01/30 07:32:54
parent author
parent permlinkeos
authoreoswing
permlinkeos-eosfactory
title手把手教你玩eos:使用EOSFactory构建和部署智能合约
body@@ -47,16 +47,169 @@ %E5%AD%A6%E4%B9%A0%E4%BA%A4%E6%B5%81%E4%B9%8B%E7%94%A8%E3%80%82%0A +!%5B%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png%5D(https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%25E6%2589%258B%25E6%258A%258A%25E6%2589%258B-%25E5%2585%25AC%25E4%25BC%2597%25E5%258F%25B7.png) %0A0.%E5%BC%95%E8%A8%80%0A0.
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png","https://cdn.steemitimages.com/DQmTCJ9gexhR1jqp793hnms6pXCiCWSQjT9mGu5duR22r8S/eost17-01.png","https://cdn.steemitimages.com/DQmXfw11QfqfJmaSj4Dkpx6uV87rwVG6fdckZsWEPaJBcjj/eost17-02.png","https://cdn.steemitimages.com/DQmUCZsHnNc8tTj8mBkV1tMkBmxax7ChVdC6p4K2QAxh3QT/eost17-03.png","https://cdn.steemitimages.com/DQmcv79WLKZxws3t4KQsMHasVi8CsCeXTFYpSJaMpYNoyjN/eost17-04.png","https://cdn.steemitimages.com/DQmSb1yUtPP76pGWcnPUPihcC55YFo7kUVk6TUHDQGxVJSU/eost17-05.png","https://cdn.steemitimages.com/DQmVefvYaP6f63DkuqnR51Gfmzqxu2XADsNcMWP9Ea32L1B/eost17-06.png","https://cdn.steemitimages.com/DQmWnTtYUZdYc71xJf8PcsqLaVsyE1FbN6BfQjaGkPFiJm2/eost17-07.png","https://cdn.steemitimages.com/DQmVL617rHBmVBkRNEo5B7t4yE6EG2AMZWtddJfFhb5W8Hd/eost17-08.png","https://cdn.steemitimages.com/DQmcxjTyR1F3rnuda33kYUGj3KKpPi4FfqAHmLHMSp4f28J/eost17-09.png","https://cdn.steemitimages.com/DQmTi3vMacE2ZjEyfG1WYi6TkCayPwvh1eceEbsaPUjd76j/eost17-10.png","https://cdn.steemitimages.com/DQmb4eMzBqeMjR38pZF6Q9HGXqMTm3Cz9Juz4ByGpzm94ye/eost17-11.png","https://cdn.steemitimages.com/DQmR1VVQhYXsQyLJqmv3GXYPZGue9BZMB7WGnfzd81xiYBz/eost17-12.png"],"links":["http://eosfactory.io/build/html/tutorials/03.BuildingAndDeployingEOSContractsInEOSFactory.html"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #29902597/Trx 27cf521c8d18ca0e994ff604bc8bd56a4e36e2fc
View Raw JSON Data
{
  "trx_id": "27cf521c8d18ca0e994ff604bc8bd56a4e36e2fc",
  "block": 29902597,
  "trx_in_block": 34,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-30T07:32:54",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-eosfactory",
      "title": "手把手教你玩eos:使用EOSFactory构建和部署智能合约",
      "body": "@@ -47,16 +47,169 @@\n %E5%AD%A6%E4%B9%A0%E4%BA%A4%E6%B5%81%E4%B9%8B%E7%94%A8%E3%80%82%0A\n+!%5B%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png%5D(https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%25E6%2589%258B%25E6%258A%258A%25E6%2589%258B-%25E5%2585%25AC%25E4%25BC%2597%25E5%258F%25B7.png)\n %0A0.%E5%BC%95%E8%A8%80%0A0.\n",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png\",\"https://cdn.steemitimages.com/DQmTCJ9gexhR1jqp793hnms6pXCiCWSQjT9mGu5duR22r8S/eost17-01.png\",\"https://cdn.steemitimages.com/DQmXfw11QfqfJmaSj4Dkpx6uV87rwVG6fdckZsWEPaJBcjj/eost17-02.png\",\"https://cdn.steemitimages.com/DQmUCZsHnNc8tTj8mBkV1tMkBmxax7ChVdC6p4K2QAxh3QT/eost17-03.png\",\"https://cdn.steemitimages.com/DQmcv79WLKZxws3t4KQsMHasVi8CsCeXTFYpSJaMpYNoyjN/eost17-04.png\",\"https://cdn.steemitimages.com/DQmSb1yUtPP76pGWcnPUPihcC55YFo7kUVk6TUHDQGxVJSU/eost17-05.png\",\"https://cdn.steemitimages.com/DQmVefvYaP6f63DkuqnR51Gfmzqxu2XADsNcMWP9Ea32L1B/eost17-06.png\",\"https://cdn.steemitimages.com/DQmWnTtYUZdYc71xJf8PcsqLaVsyE1FbN6BfQjaGkPFiJm2/eost17-07.png\",\"https://cdn.steemitimages.com/DQmVL617rHBmVBkRNEo5B7t4yE6EG2AMZWtddJfFhb5W8Hd/eost17-08.png\",\"https://cdn.steemitimages.com/DQmcxjTyR1F3rnuda33kYUGj3KKpPi4FfqAHmLHMSp4f28J/eost17-09.png\",\"https://cdn.steemitimages.com/DQmTi3vMacE2ZjEyfG1WYi6TkCayPwvh1eceEbsaPUjd76j/eost17-10.png\",\"https://cdn.steemitimages.com/DQmb4eMzBqeMjR38pZF6Q9HGXqMTm3Cz9Juz4ByGpzm94ye/eost17-11.png\",\"https://cdn.steemitimages.com/DQmR1VVQhYXsQyLJqmv3GXYPZGue9BZMB7WGnfzd81xiYBz/eost17-12.png\"],\"links\":[\"http://eosfactory.io/build/html/tutorials/03.BuildingAndDeployingEOSContractsInEOSFactory.html\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingpublished a new post: eos-eosfactory
2019/01/30 07:30:33
parent author
parent permlinkeos
authoreoswing
permlinkeos-eosfactory
title手把手教你玩eos:使用EOSFactory构建和部署智能合约
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十七篇。本篇教程讲解如何使用EOSFactory执行最简单的开发周期:创建新合约,编辑代码,构建合约,部署合约并与之交互。 0.2 学习内容 1.创建新合约 2.编译和部署合约 3.测试合约 4.修改代码,重新编译部署 0.3 机器环境 ●笔记本电脑 ●操作系统:Windows 10 1 创建新合约 1.1 进入环境 首先进入WSL中的ubuntu的命令行,然后运行Python CLI。 python3 进入Python shell后,导入EOSFactory库。 from eosfactory.eosf import * 1.2 使用模板创建新合约 从预定义模板创建新合约,第一个参数为合约名称,第二个参数为模板名称。 contract = ContractBuilder(project_from_template("foo_bar", template="01_hello_world")) ![eost17-01.png](https://cdn.steemitimages.com/DQmTCJ9gexhR1jqp793hnms6pXCiCWSQjT9mGu5duR22r8S/eost17-01.png) 查看新建合约所在路径 contract.path() ![eost17-02.png](https://cdn.steemitimages.com/DQmXfw11QfqfJmaSj4Dkpx6uV87rwVG6fdckZsWEPaJBcjj/eost17-02.png) 1.3 编辑源代码 使用你常用的编辑器打开合约路径下的src/foo_bar.cpp。 我使用的是Notepad++编辑器。 这里我们简单修改一下。把权限验证的第16行代码注释掉。 ![eost17-03.png](https://cdn.steemitimages.com/DQmUCZsHnNc8tTj8mBkV1tMkBmxax7ChVdC6p4K2QAxh3QT/eost17-03.png) 2 编译和部署合约 2.1 编译合约 可以逐个编译生成ABI文件和WAST文件。 也可以用contract.build()一次编译两个文件。 这里我们使用逐个编译。 contract.build_abi() contract.build_wast() ![eost17-04.png](https://cdn.steemitimages.com/DQmcv79WLKZxws3t4KQsMHasVi8CsCeXTFYpSJaMpYNoyjN/eost17-04.png) 2.2 部署合约上链 初始化本地testnet reset() ![eost17-05.png](https://cdn.steemitimages.com/DQmSb1yUtPP76pGWcnPUPihcC55YFo7kUVk6TUHDQGxVJSU/eost17-05.png) 创建主账户master create_master_account("master") ![eost17-06.png](https://cdn.steemitimages.com/DQmVefvYaP6f63DkuqnR51Gfmzqxu2XADsNcMWP9Ea32L1B/eost17-06.png) 使用master主账号创建合约账户host create_account("host", master) ![eost17-07.png](https://cdn.steemitimages.com/DQmWnTtYUZdYc71xJf8PcsqLaVsyE1FbN6BfQjaGkPFiJm2/eost17-07.png) 将账户host和合约绑定。 contract = Contract(host, contract.path()) 部署合约。 contract.deploy() ![eost17-08.png](https://cdn.steemitimages.com/DQmVL617rHBmVBkRNEo5B7t4yE6EG2AMZWtddJfFhb5W8Hd/eost17-08.png) 3 测试合约 3.1 创建测试账号 create_account("alice", master) create_account("carol", master) ![eost17-09.png](https://cdn.steemitimages.com/DQmcxjTyR1F3rnuda33kYUGj3KKpPi4FfqAHmLHMSp4f28J/eost17-09.png) 3.2 调用合约 contract.push_action("hi", {"user":alice}, permission=alice) contract.push_action("hi", {"user":alice}, permission=carol) ![eost17-10.png](https://cdn.steemitimages.com/DQmTi3vMacE2ZjEyfG1WYi6TkCayPwvh1eceEbsaPUjd76j/eost17-10.png) 因为我们注释掉了权限验证代码行。 所以,用alice签名还是用carol签名User为alice,都能顺利通过。 4 修改代码,重新编译部署 4.1 修改代码 打开合约路径下的src/foo_bar.cpp,这次将第16行的权限验证代码取消注释,使之生效。 ![eost17-11.png](https://cdn.steemitimages.com/DQmb4eMzBqeMjR38pZF6Q9HGXqMTm3Cz9Juz4ByGpzm94ye/eost17-11.png) 4.2 重新编译合约 contract.build() 4.3 重新部署合约 contract.deploy() 4.4 测试合约 再次调用合约 contract.push_action("hi", {"user":alice}, permission=alice) contract.push_action("hi", {"user":alice}, permission=carol) ![eost17-12.png](https://cdn.steemitimages.com/DQmR1VVQhYXsQyLJqmv3GXYPZGue9BZMB7WGnfzd81xiYBz/eost17-12.png) 会发现用alice签名User为alice通过。 而用carol签名User为alice,提示没有权限。 说明权限代码生效。 4.5 清理环境 关闭本地testnet stop() 退出Python CLI exit() 5 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: 使用EOSFactory构建和部署智能合约: ●http://eosfactory.io/build/html/tutorials/03.BuildingAndDeployingEOSContractsInEOSFactory.html 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmTCJ9gexhR1jqp793hnms6pXCiCWSQjT9mGu5duR22r8S/eost17-01.png","https://cdn.steemitimages.com/DQmXfw11QfqfJmaSj4Dkpx6uV87rwVG6fdckZsWEPaJBcjj/eost17-02.png","https://cdn.steemitimages.com/DQmUCZsHnNc8tTj8mBkV1tMkBmxax7ChVdC6p4K2QAxh3QT/eost17-03.png","https://cdn.steemitimages.com/DQmcv79WLKZxws3t4KQsMHasVi8CsCeXTFYpSJaMpYNoyjN/eost17-04.png","https://cdn.steemitimages.com/DQmSb1yUtPP76pGWcnPUPihcC55YFo7kUVk6TUHDQGxVJSU/eost17-05.png","https://cdn.steemitimages.com/DQmVefvYaP6f63DkuqnR51Gfmzqxu2XADsNcMWP9Ea32L1B/eost17-06.png","https://cdn.steemitimages.com/DQmWnTtYUZdYc71xJf8PcsqLaVsyE1FbN6BfQjaGkPFiJm2/eost17-07.png","https://cdn.steemitimages.com/DQmVL617rHBmVBkRNEo5B7t4yE6EG2AMZWtddJfFhb5W8Hd/eost17-08.png","https://cdn.steemitimages.com/DQmcxjTyR1F3rnuda33kYUGj3KKpPi4FfqAHmLHMSp4f28J/eost17-09.png","https://cdn.steemitimages.com/DQmTi3vMacE2ZjEyfG1WYi6TkCayPwvh1eceEbsaPUjd76j/eost17-10.png","https://cdn.steemitimages.com/DQmb4eMzBqeMjR38pZF6Q9HGXqMTm3Cz9Juz4ByGpzm94ye/eost17-11.png","https://cdn.steemitimages.com/DQmR1VVQhYXsQyLJqmv3GXYPZGue9BZMB7WGnfzd81xiYBz/eost17-12.png"],"links":["http://eosfactory.io/build/html/tutorials/03.BuildingAndDeployingEOSContractsInEOSFactory.html"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #29902550/Trx 4a07462c792c2a21c61e0d714260892e6ae38cb3
View Raw JSON Data
{
  "trx_id": "4a07462c792c2a21c61e0d714260892e6ae38cb3",
  "block": 29902550,
  "trx_in_block": 8,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-30T07:30:33",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-eosfactory",
      "title": "手把手教你玩eos:使用EOSFactory构建和部署智能合约",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十七篇。本篇教程讲解如何使用EOSFactory执行最简单的开发周期:创建新合约,编辑代码,构建合约,部署合约并与之交互。\n\n0.2 学习内容\n1.创建新合约\n2.编译和部署合约\n3.测试合约\n4.修改代码,重新编译部署\n\n0.3 机器环境\n●笔记本电脑\n●操作系统:Windows 10\n\n1 创建新合约\n1.1 进入环境\n首先进入WSL中的ubuntu的命令行,然后运行Python CLI。\npython3\n进入Python shell后,导入EOSFactory库。\nfrom eosfactory.eosf import *\n\n1.2 使用模板创建新合约\n从预定义模板创建新合约,第一个参数为合约名称,第二个参数为模板名称。\ncontract = ContractBuilder(project_from_template(\"foo_bar\", template=\"01_hello_world\"))\n![eost17-01.png](https://cdn.steemitimages.com/DQmTCJ9gexhR1jqp793hnms6pXCiCWSQjT9mGu5duR22r8S/eost17-01.png)\n查看新建合约所在路径\ncontract.path()\n![eost17-02.png](https://cdn.steemitimages.com/DQmXfw11QfqfJmaSj4Dkpx6uV87rwVG6fdckZsWEPaJBcjj/eost17-02.png)\n\n1.3 编辑源代码\n使用你常用的编辑器打开合约路径下的src/foo_bar.cpp。\n我使用的是Notepad++编辑器。\n这里我们简单修改一下。把权限验证的第16行代码注释掉。\n![eost17-03.png](https://cdn.steemitimages.com/DQmUCZsHnNc8tTj8mBkV1tMkBmxax7ChVdC6p4K2QAxh3QT/eost17-03.png)\n\n2 编译和部署合约\n2.1 编译合约\n可以逐个编译生成ABI文件和WAST文件。\n也可以用contract.build()一次编译两个文件。\n这里我们使用逐个编译。\ncontract.build_abi()\ncontract.build_wast()\n![eost17-04.png](https://cdn.steemitimages.com/DQmcv79WLKZxws3t4KQsMHasVi8CsCeXTFYpSJaMpYNoyjN/eost17-04.png)\n\n2.2 部署合约上链\n初始化本地testnet\nreset()\n![eost17-05.png](https://cdn.steemitimages.com/DQmSb1yUtPP76pGWcnPUPihcC55YFo7kUVk6TUHDQGxVJSU/eost17-05.png)\n创建主账户master\ncreate_master_account(\"master\")\n![eost17-06.png](https://cdn.steemitimages.com/DQmVefvYaP6f63DkuqnR51Gfmzqxu2XADsNcMWP9Ea32L1B/eost17-06.png)\n使用master主账号创建合约账户host\ncreate_account(\"host\", master)\n![eost17-07.png](https://cdn.steemitimages.com/DQmWnTtYUZdYc71xJf8PcsqLaVsyE1FbN6BfQjaGkPFiJm2/eost17-07.png)\n将账户host和合约绑定。\ncontract = Contract(host, contract.path())\n部署合约。\ncontract.deploy()\n![eost17-08.png](https://cdn.steemitimages.com/DQmVL617rHBmVBkRNEo5B7t4yE6EG2AMZWtddJfFhb5W8Hd/eost17-08.png)\n\n3 测试合约\n3.1 创建测试账号\ncreate_account(\"alice\", master)\ncreate_account(\"carol\", master)\n![eost17-09.png](https://cdn.steemitimages.com/DQmcxjTyR1F3rnuda33kYUGj3KKpPi4FfqAHmLHMSp4f28J/eost17-09.png)\n\n3.2 调用合约\ncontract.push_action(\"hi\", {\"user\":alice}, permission=alice)\ncontract.push_action(\"hi\", {\"user\":alice}, permission=carol)\n![eost17-10.png](https://cdn.steemitimages.com/DQmTi3vMacE2ZjEyfG1WYi6TkCayPwvh1eceEbsaPUjd76j/eost17-10.png)\n因为我们注释掉了权限验证代码行。\n所以,用alice签名还是用carol签名User为alice,都能顺利通过。\n\n4 修改代码,重新编译部署\n4.1 修改代码\n打开合约路径下的src/foo_bar.cpp,这次将第16行的权限验证代码取消注释,使之生效。\n![eost17-11.png](https://cdn.steemitimages.com/DQmb4eMzBqeMjR38pZF6Q9HGXqMTm3Cz9Juz4ByGpzm94ye/eost17-11.png)\n\n4.2 重新编译合约\ncontract.build()\n4.3 重新部署合约\ncontract.deploy()\n4.4 测试合约\n再次调用合约\ncontract.push_action(\"hi\", {\"user\":alice}, permission=alice)\ncontract.push_action(\"hi\", {\"user\":alice}, permission=carol)\n![eost17-12.png](https://cdn.steemitimages.com/DQmR1VVQhYXsQyLJqmv3GXYPZGue9BZMB7WGnfzd81xiYBz/eost17-12.png)\n会发现用alice签名User为alice通过。\n而用carol签名User为alice,提示没有权限。\n说明权限代码生效。\n\n4.5 清理环境\n关闭本地testnet\nstop()\n退出Python CLI\nexit()\n\n5 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n使用EOSFactory构建和部署智能合约: ●http://eosfactory.io/build/html/tutorials/03.BuildingAndDeployingEOSContractsInEOSFactory.html\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmTCJ9gexhR1jqp793hnms6pXCiCWSQjT9mGu5duR22r8S/eost17-01.png\",\"https://cdn.steemitimages.com/DQmXfw11QfqfJmaSj4Dkpx6uV87rwVG6fdckZsWEPaJBcjj/eost17-02.png\",\"https://cdn.steemitimages.com/DQmUCZsHnNc8tTj8mBkV1tMkBmxax7ChVdC6p4K2QAxh3QT/eost17-03.png\",\"https://cdn.steemitimages.com/DQmcv79WLKZxws3t4KQsMHasVi8CsCeXTFYpSJaMpYNoyjN/eost17-04.png\",\"https://cdn.steemitimages.com/DQmSb1yUtPP76pGWcnPUPihcC55YFo7kUVk6TUHDQGxVJSU/eost17-05.png\",\"https://cdn.steemitimages.com/DQmVefvYaP6f63DkuqnR51Gfmzqxu2XADsNcMWP9Ea32L1B/eost17-06.png\",\"https://cdn.steemitimages.com/DQmWnTtYUZdYc71xJf8PcsqLaVsyE1FbN6BfQjaGkPFiJm2/eost17-07.png\",\"https://cdn.steemitimages.com/DQmVL617rHBmVBkRNEo5B7t4yE6EG2AMZWtddJfFhb5W8Hd/eost17-08.png\",\"https://cdn.steemitimages.com/DQmcxjTyR1F3rnuda33kYUGj3KKpPi4FfqAHmLHMSp4f28J/eost17-09.png\",\"https://cdn.steemitimages.com/DQmTi3vMacE2ZjEyfG1WYi6TkCayPwvh1eceEbsaPUjd76j/eost17-10.png\",\"https://cdn.steemitimages.com/DQmb4eMzBqeMjR38pZF6Q9HGXqMTm3Cz9Juz4ByGpzm94ye/eost17-11.png\",\"https://cdn.steemitimages.com/DQmR1VVQhYXsQyLJqmv3GXYPZGue9BZMB7WGnfzd81xiYBz/eost17-12.png\"],\"links\":[\"http://eosfactory.io/build/html/tutorials/03.BuildingAndDeployingEOSContractsInEOSFactory.html\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2019/01/24 09:04:42
votergreencmetaha
authoreoswing
permlinkeos-eosfactory-eos
weight10000 (100.00%)
Transaction InfoBlock #29731803/Trx 27b9e8153d39b3d3783da71099b7d2ebdbf614e1
View Raw JSON Data
{
  "trx_id": "27b9e8153d39b3d3783da71099b7d2ebdbf614e1",
  "block": 29731803,
  "trx_in_block": 20,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-24T09:04:42",
  "op": [
    "vote",
    {
      "voter": "greencmetaha",
      "author": "eoswing",
      "permlink": "eos-eosfactory-eos",
      "weight": 10000
    }
  ]
}
eoswingpublished a new post: eos-eosfactory-eos
2019/01/24 08:54:39
parent author
parent permlinkeos
authoreoswing
permlinkeos-eosfactory-eos
title手把手教你玩eos:使用EOSFactory与EOS交互
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![手把手-公众号.png](https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十六篇。本篇教程讲解如何使用EOSFactory及其Python CLI轻松直观地与EOS进行交互。 0.2 学习内容 启动本地测试节点 管理账户和智能合约 运行测试合约 清理环境 0.3 机器环境 ●笔记本电脑 ●操作系统:Windows 10 1 启动本地测试节点 1.1 进入环境 首先进入WSL中的ubuntu的命令行,然后运行Python CLI。 Python3 ![eost16-01.png](https://cdn.steemitimages.com/DQmTCXkVCsRvWovbR2XFRUJcJzry3VQp9a6BJzXZdLwSLTy/eost16-01.png) 进入Python shell后,导入EOSFactory库。 from eosfactory.eosf import * 1.2 启动本地测试节点(testnet) 启动单节点本地testnet。 reset() ![eost16-02.png](https://cdn.steemitimages.com/DQmTM2kzhgpCDWU4U2ynBu9o34LAJmuauijDRJLS4zQtgpA/eost16-02.png) 获取testnet当前状态的信息。 info() ![eost16-03.png](https://cdn.steemitimages.com/DQmVfXh8CKY7Gg1WaF3j3HVtk1chmWzY8LNzaBFhrrwK8pt/eost16-03.png) 1.3 管理本地testnet 要停止当前的testnet。 stop() ![eost16-04.png](https://cdn.steemitimages.com/DQmQ5YSnxdmJAaTqMtUXAuFWBshwfB1RvMYE9SUZav2NPZJ/eost16-04.png) 要继续运行当前的testnet。 resume() ![eost16-05.png](https://cdn.steemitimages.com/DQmVMjsmqijFFGQEn5p6hvZ1WJJsoprExhiXrw5u6q1JU9s/eost16-05.png) 停止当前的testnet并启动一个新的。 reset() ![eost16-06.png](https://cdn.steemitimages.com/DQmX5BFaZFWx2Qp7tnXM8w5LvyLc651yHM9xz6KYrvepTUh/eost16-06.png) 2 管理账户和智能合约 2.1 创建主账户 首先,确保本地testnet正在运行。 info()查看,没有就reset()启动一个。 创建一个可以创建其他帐户的主帐户,名称为master。当然,你也可以取其他名称: create_master_account("master") ![eost16-07.png](https://cdn.steemitimages.com/DQmcd2uS3b3HXa33pHjWjFxyFbTgc5Vabk9Dwvc9MyTc7Pt/eost16-07.png) 注意:名称master只是全局变量的名称,而不是区块链上创建的帐户的实际名称。 您无需担心锁定或解锁钱包,管理其密码或将私钥导入其中。所有这一切都由EOSFactory来处理。 查看master主账户信息。 master.info() ![eost16-08.png](https://cdn.steemitimages.com/DQmdoBAfuadU6LpVLD7ZSobs8RUnNbUBxGzZQfYEbWKL7oS/eost16-08.png) 2.2 创建子账户 使用master创建测试帐户: create_account("charlie", master) ![eost16-09.png](https://cdn.steemitimages.com/DQmRixG4GNd7rB5zUjLRtQa2ksNyfyTApA95sS9gjZg81hK/eost16-09.png) 查看账户信息: charlie.info() ![eost16-10.png](https://cdn.steemitimages.com/DQmTVV6ErrYSAotJxjqWcRv8hkLTobvJL4ZMkYnAkA5ekQQ/eost16-10.png) 和上面的master一样,名称charlie只是全局变量的名称,而不是区块链上创建的帐户的实际名称。 如果你想命名EOS链上的账号名,可以使用参数account_name。 下面创建一个命名链上账号名的账户charlie2。 create_account("charlie2", master, account_name="charlie22eos") ![eost16-11.png](https://cdn.steemitimages.com/DQmVQ2sb1Fa7oE1AMBZVb3Bb6WKobnvKDZzbECUc2LnvHhN/eost16-11.png) 查看charlie2的账户信息: charlie2.info() ![eost16-12.png](https://cdn.steemitimages.com/DQmXM1PBrQMNeLzQXbAe2779kALrKWsEvvBqSRb8tZMfpLd/eost16-12.png) 2.3 管理智能合约 定义contract 创建一个部署智能合约用的账户host create_account("host", master) ![eost16-13.png](https://cdn.steemitimages.com/DQmWbY1mXGDZXE3gFyvCDC1e6LdwAN1gwv7qcEz8C7jpEgt/eost16-13.png) 定义contract,将账户和智能合约所在文件夹绑定。 contract = Contract(host, "/mnt/f/EOS/eosfactory/contracts/02_eosio_token") 构建合约 contract.build() ![eost16-14.png](https://cdn.steemitimages.com/DQmP3zFmiG9dw6EwgkYWgyKQUZsq7uUhe317mtDw754yQMh/eost16-14.png) 部署合约 可以使用code()来检查合约。首先我们看下没有部署合约的code()提示。 contract.code() ![eost16-15.png](https://cdn.steemitimages.com/DQmXJU4CTjdZMZZPPCgeCUHCjm2DYS7oxJsUuPxrrS2HKYW/eost16-15.png) 部署合约: contract.deploy() ![eost16-16.png](https://cdn.steemitimages.com/DQmafMoqcsy7ZjnPXj8cfnsd4PQb4fEk89Cic221QAXXEXm/eost16-16.png) 再次查看合约hash: ![eost16-17.png](https://cdn.steemitimages.com/DQmYzRQUvjK2cZjYSxoapVh7jaQzBo6wB7EwpQkhqvHgL3E/eost16-17.png) 3 运行测试合约 3.1 创建代币 首先创建10亿的EOS代币。 host.push_action( "create", { "issuer": master, "maximum_supply": "1000000000.0000 EOS", "can_freeze": "0", "can_recall": "0", "can_whitelist": "0" }, [master, host]) ![eost16-18.png](https://cdn.steemitimages.com/DQmfZkU1udMk1QwnboiU8wBLnp1J22Z4a5jw9iXTRA6u8A9/eost16-18.png) 注意:该push_action方法有三个参数:操作的名称,JSON格式的操作参数以及需要权限的帐户。 注意:如果您想要在不广播的情况下查看实际交易,请使用show_action方法代替push_action。 3.2 发放代币 发给charlie代币100EOS。 host.push_action( "issue", { "to": charlie, "quantity": "100.0000 EOS", "memo": "" }, master) ![eost16-19.png](https://cdn.steemitimages.com/DQmZPZSSvqG2ZZUgg83Vf8KdCDzB9BTtjtWrQHi66NzsPNt/eost16-19.png) 查看下charlie当前账户信息 host.table("accounts", charlie) ![eost16-20.png](https://cdn.steemitimages.com/DQmQMpQDAz26JxA15ttTvAUqdToV7zcbAQjnpTe4tXoBT1X/eost16-20.png) 3.3 代币转账 现在charlie的代币转账25EOS给charlie2。 host.push_action( "transfer", { "from": charlie, "to": charlie2, "quantity": "25.0000 EOS", "memo":"" }, charlie) ![eost16-21.png](https://cdn.steemitimages.com/DQmNwLnB4PGhzdvjqJmfPzzfrg7NM47SK1grz8TWDTFKFP5/eost16-21.png) 再次查看charlie账户信息 host.table("accounts", charlie) ![eost16-22.png](https://cdn.steemitimages.com/DQmWPfSJL5UzU4PQnUmR8v17PcxYvfWEqD8p5MhMbL8WwS5/eost16-22.png) 查看charlie2账户信息 host.table("accounts", charlie2) ![eost16-23.png](https://cdn.steemitimages.com/DQmbHPjuXGnFunwyC1m65WeX6YLcp3atuViWiXdaACpR7An/eost16-23.png) 可以看出,已经转账到位。 4 清理环境 4.1 关闭本地testnet stop() ![eost16-24.png](https://cdn.steemitimages.com/DQmfVhbybw8q81CKEMVcMp55QRxMh1iy4V4UHntRC3eH8QR/eost16-24.png) 4.2 退出Python CLI exit() ![eost16-25.png](https://cdn.steemitimages.com/DQmbj2LbaKbjozfKqyvmX8LoRXWu8XN58KaRdhBf57nKBCv/eost16-25.png) 5 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: ●使用EOSFactory与EOS交互: http://eosfactory.io/build/html/tutorials/02.InteractingWithEOSContractsInEOSFactory.html 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png","https://cdn.steemitimages.com/DQmTCXkVCsRvWovbR2XFRUJcJzry3VQp9a6BJzXZdLwSLTy/eost16-01.png","https://cdn.steemitimages.com/DQmTM2kzhgpCDWU4U2ynBu9o34LAJmuauijDRJLS4zQtgpA/eost16-02.png","https://cdn.steemitimages.com/DQmVfXh8CKY7Gg1WaF3j3HVtk1chmWzY8LNzaBFhrrwK8pt/eost16-03.png","https://cdn.steemitimages.com/DQmQ5YSnxdmJAaTqMtUXAuFWBshwfB1RvMYE9SUZav2NPZJ/eost16-04.png","https://cdn.steemitimages.com/DQmVMjsmqijFFGQEn5p6hvZ1WJJsoprExhiXrw5u6q1JU9s/eost16-05.png","https://cdn.steemitimages.com/DQmX5BFaZFWx2Qp7tnXM8w5LvyLc651yHM9xz6KYrvepTUh/eost16-06.png","https://cdn.steemitimages.com/DQmcd2uS3b3HXa33pHjWjFxyFbTgc5Vabk9Dwvc9MyTc7Pt/eost16-07.png","https://cdn.steemitimages.com/DQmdoBAfuadU6LpVLD7ZSobs8RUnNbUBxGzZQfYEbWKL7oS/eost16-08.png","https://cdn.steemitimages.com/DQmRixG4GNd7rB5zUjLRtQa2ksNyfyTApA95sS9gjZg81hK/eost16-09.png","https://cdn.steemitimages.com/DQmTVV6ErrYSAotJxjqWcRv8hkLTobvJL4ZMkYnAkA5ekQQ/eost16-10.png","https://cdn.steemitimages.com/DQmVQ2sb1Fa7oE1AMBZVb3Bb6WKobnvKDZzbECUc2LnvHhN/eost16-11.png","https://cdn.steemitimages.com/DQmXM1PBrQMNeLzQXbAe2779kALrKWsEvvBqSRb8tZMfpLd/eost16-12.png","https://cdn.steemitimages.com/DQmWbY1mXGDZXE3gFyvCDC1e6LdwAN1gwv7qcEz8C7jpEgt/eost16-13.png","https://cdn.steemitimages.com/DQmP3zFmiG9dw6EwgkYWgyKQUZsq7uUhe317mtDw754yQMh/eost16-14.png","https://cdn.steemitimages.com/DQmXJU4CTjdZMZZPPCgeCUHCjm2DYS7oxJsUuPxrrS2HKYW/eost16-15.png","https://cdn.steemitimages.com/DQmafMoqcsy7ZjnPXj8cfnsd4PQb4fEk89Cic221QAXXEXm/eost16-16.png","https://cdn.steemitimages.com/DQmYzRQUvjK2cZjYSxoapVh7jaQzBo6wB7EwpQkhqvHgL3E/eost16-17.png","https://cdn.steemitimages.com/DQmfZkU1udMk1QwnboiU8wBLnp1J22Z4a5jw9iXTRA6u8A9/eost16-18.png","https://cdn.steemitimages.com/DQmZPZSSvqG2ZZUgg83Vf8KdCDzB9BTtjtWrQHi66NzsPNt/eost16-19.png","https://cdn.steemitimages.com/DQmQMpQDAz26JxA15ttTvAUqdToV7zcbAQjnpTe4tXoBT1X/eost16-20.png","https://cdn.steemitimages.com/DQmNwLnB4PGhzdvjqJmfPzzfrg7NM47SK1grz8TWDTFKFP5/eost16-21.png","https://cdn.steemitimages.com/DQmWPfSJL5UzU4PQnUmR8v17PcxYvfWEqD8p5MhMbL8WwS5/eost16-22.png","https://cdn.steemitimages.com/DQmbHPjuXGnFunwyC1m65WeX6YLcp3atuViWiXdaACpR7An/eost16-23.png","https://cdn.steemitimages.com/DQmfVhbybw8q81CKEMVcMp55QRxMh1iy4V4UHntRC3eH8QR/eost16-24.png","https://cdn.steemitimages.com/DQmbj2LbaKbjozfKqyvmX8LoRXWu8XN58KaRdhBf57nKBCv/eost16-25.png"],"links":["http://eosfactory.io/build/html/tutorials/02.InteractingWithEOSContractsInEOSFactory.html"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #29731603/Trx 503f30edd4afa74997bc8af97e6cd1980bfc69eb
View Raw JSON Data
{
  "trx_id": "503f30edd4afa74997bc8af97e6cd1980bfc69eb",
  "block": 29731603,
  "trx_in_block": 25,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-24T08:54:39",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-eosfactory-eos",
      "title": "手把手教你玩eos:使用EOSFactory与EOS交互",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![手把手-公众号.png](https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png)\n\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十六篇。本篇教程讲解如何使用EOSFactory及其Python CLI轻松直观地与EOS进行交互。\n\n0.2 学习内容\n启动本地测试节点\n管理账户和智能合约\n运行测试合约\n清理环境\n\n0.3 机器环境\n●笔记本电脑\n●操作系统:Windows 10\n\n1 启动本地测试节点\n1.1 进入环境\n首先进入WSL中的ubuntu的命令行,然后运行Python CLI。\nPython3\n![eost16-01.png](https://cdn.steemitimages.com/DQmTCXkVCsRvWovbR2XFRUJcJzry3VQp9a6BJzXZdLwSLTy/eost16-01.png)\n进入Python shell后,导入EOSFactory库。\nfrom eosfactory.eosf import *\n\n1.2 启动本地测试节点(testnet)\n启动单节点本地testnet。\nreset()\n![eost16-02.png](https://cdn.steemitimages.com/DQmTM2kzhgpCDWU4U2ynBu9o34LAJmuauijDRJLS4zQtgpA/eost16-02.png)\n获取testnet当前状态的信息。\ninfo()\n![eost16-03.png](https://cdn.steemitimages.com/DQmVfXh8CKY7Gg1WaF3j3HVtk1chmWzY8LNzaBFhrrwK8pt/eost16-03.png)\n\n1.3 管理本地testnet\n要停止当前的testnet。\nstop()\n![eost16-04.png](https://cdn.steemitimages.com/DQmQ5YSnxdmJAaTqMtUXAuFWBshwfB1RvMYE9SUZav2NPZJ/eost16-04.png)\n要继续运行当前的testnet。\nresume()\n![eost16-05.png](https://cdn.steemitimages.com/DQmVMjsmqijFFGQEn5p6hvZ1WJJsoprExhiXrw5u6q1JU9s/eost16-05.png)\n停止当前的testnet并启动一个新的。\nreset()\n![eost16-06.png](https://cdn.steemitimages.com/DQmX5BFaZFWx2Qp7tnXM8w5LvyLc651yHM9xz6KYrvepTUh/eost16-06.png)\n\n2 管理账户和智能合约\n2.1 创建主账户\n首先,确保本地testnet正在运行。\ninfo()查看,没有就reset()启动一个。\n创建一个可以创建其他帐户的主帐户,名称为master。当然,你也可以取其他名称:\ncreate_master_account(\"master\")\n![eost16-07.png](https://cdn.steemitimages.com/DQmcd2uS3b3HXa33pHjWjFxyFbTgc5Vabk9Dwvc9MyTc7Pt/eost16-07.png)\n注意:名称master只是全局变量的名称,而不是区块链上创建的帐户的实际名称。\n您无需担心锁定或解锁钱包,管理其密码或将私钥导入其中。所有这一切都由EOSFactory来处理。\n查看master主账户信息。\nmaster.info()\n![eost16-08.png](https://cdn.steemitimages.com/DQmdoBAfuadU6LpVLD7ZSobs8RUnNbUBxGzZQfYEbWKL7oS/eost16-08.png)\n\n2.2 创建子账户\n使用master创建测试帐户:\ncreate_account(\"charlie\", master)\n![eost16-09.png](https://cdn.steemitimages.com/DQmRixG4GNd7rB5zUjLRtQa2ksNyfyTApA95sS9gjZg81hK/eost16-09.png)\n查看账户信息:\ncharlie.info()\n![eost16-10.png](https://cdn.steemitimages.com/DQmTVV6ErrYSAotJxjqWcRv8hkLTobvJL4ZMkYnAkA5ekQQ/eost16-10.png)\n和上面的master一样,名称charlie只是全局变量的名称,而不是区块链上创建的帐户的实际名称。\n如果你想命名EOS链上的账号名,可以使用参数account_name。\n下面创建一个命名链上账号名的账户charlie2。\ncreate_account(\"charlie2\", master, account_name=\"charlie22eos\")\n![eost16-11.png](https://cdn.steemitimages.com/DQmVQ2sb1Fa7oE1AMBZVb3Bb6WKobnvKDZzbECUc2LnvHhN/eost16-11.png)\n查看charlie2的账户信息:\ncharlie2.info()\n![eost16-12.png](https://cdn.steemitimages.com/DQmXM1PBrQMNeLzQXbAe2779kALrKWsEvvBqSRb8tZMfpLd/eost16-12.png)\n\n2.3 管理智能合约\n定义contract\n创建一个部署智能合约用的账户host\ncreate_account(\"host\", master)\n![eost16-13.png](https://cdn.steemitimages.com/DQmWbY1mXGDZXE3gFyvCDC1e6LdwAN1gwv7qcEz8C7jpEgt/eost16-13.png)\n定义contract,将账户和智能合约所在文件夹绑定。\ncontract = Contract(host, \"/mnt/f/EOS/eosfactory/contracts/02_eosio_token\")\n构建合约\ncontract.build()\n![eost16-14.png](https://cdn.steemitimages.com/DQmP3zFmiG9dw6EwgkYWgyKQUZsq7uUhe317mtDw754yQMh/eost16-14.png)\n部署合约\n可以使用code()来检查合约。首先我们看下没有部署合约的code()提示。\ncontract.code()\n![eost16-15.png](https://cdn.steemitimages.com/DQmXJU4CTjdZMZZPPCgeCUHCjm2DYS7oxJsUuPxrrS2HKYW/eost16-15.png)\n部署合约:\ncontract.deploy()\n![eost16-16.png](https://cdn.steemitimages.com/DQmafMoqcsy7ZjnPXj8cfnsd4PQb4fEk89Cic221QAXXEXm/eost16-16.png)\n再次查看合约hash:\n![eost16-17.png](https://cdn.steemitimages.com/DQmYzRQUvjK2cZjYSxoapVh7jaQzBo6wB7EwpQkhqvHgL3E/eost16-17.png)\n\n3 运行测试合约\n3.1 创建代币\n首先创建10亿的EOS代币。\nhost.push_action(\n   \"create\", \n   {\n       \"issuer\": master,\n       \"maximum_supply\": \"1000000000.0000 EOS\",\n       \"can_freeze\": \"0\",\n       \"can_recall\": \"0\",\n       \"can_whitelist\": \"0\"\n   }, [master, host])\n![eost16-18.png](https://cdn.steemitimages.com/DQmfZkU1udMk1QwnboiU8wBLnp1J22Z4a5jw9iXTRA6u8A9/eost16-18.png)\n注意:该push_action方法有三个参数:操作的名称,JSON格式的操作参数以及需要权限的帐户。\n注意:如果您想要在不广播的情况下查看实际交易,请使用show_action方法代替push_action。\n\n3.2 发放代币\n发给charlie代币100EOS。\nhost.push_action(\n   \"issue\",\n   {\n       \"to\": charlie, \"quantity\": \"100.0000 EOS\", \"memo\": \"\"\n   },\n   master)\n![eost16-19.png](https://cdn.steemitimages.com/DQmZPZSSvqG2ZZUgg83Vf8KdCDzB9BTtjtWrQHi66NzsPNt/eost16-19.png)\n查看下charlie当前账户信息\nhost.table(\"accounts\", charlie)\n![eost16-20.png](https://cdn.steemitimages.com/DQmQMpQDAz26JxA15ttTvAUqdToV7zcbAQjnpTe4tXoBT1X/eost16-20.png)\n\n3.3 代币转账\n现在charlie的代币转账25EOS给charlie2。\nhost.push_action(\n   \"transfer\",\n   {\n       \"from\": charlie, \"to\": charlie2,\n       \"quantity\": \"25.0000 EOS\", \"memo\":\"\"\n   },\n   charlie)\n![eost16-21.png](https://cdn.steemitimages.com/DQmNwLnB4PGhzdvjqJmfPzzfrg7NM47SK1grz8TWDTFKFP5/eost16-21.png)\n再次查看charlie账户信息\nhost.table(\"accounts\", charlie)\n![eost16-22.png](https://cdn.steemitimages.com/DQmWPfSJL5UzU4PQnUmR8v17PcxYvfWEqD8p5MhMbL8WwS5/eost16-22.png)\n查看charlie2账户信息\nhost.table(\"accounts\", charlie2)\n![eost16-23.png](https://cdn.steemitimages.com/DQmbHPjuXGnFunwyC1m65WeX6YLcp3atuViWiXdaACpR7An/eost16-23.png)\n可以看出,已经转账到位。\n\n4 清理环境\n4.1 关闭本地testnet\nstop()\n![eost16-24.png](https://cdn.steemitimages.com/DQmfVhbybw8q81CKEMVcMp55QRxMh1iy4V4UHntRC3eH8QR/eost16-24.png)\n\n4.2 退出Python CLI\nexit()\n![eost16-25.png](https://cdn.steemitimages.com/DQmbj2LbaKbjozfKqyvmX8LoRXWu8XN58KaRdhBf57nKBCv/eost16-25.png)\n\n5 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n●使用EOSFactory与EOS交互: http://eosfactory.io/build/html/tutorials/02.InteractingWithEOSContractsInEOSFactory.html\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png\",\"https://cdn.steemitimages.com/DQmTCXkVCsRvWovbR2XFRUJcJzry3VQp9a6BJzXZdLwSLTy/eost16-01.png\",\"https://cdn.steemitimages.com/DQmTM2kzhgpCDWU4U2ynBu9o34LAJmuauijDRJLS4zQtgpA/eost16-02.png\",\"https://cdn.steemitimages.com/DQmVfXh8CKY7Gg1WaF3j3HVtk1chmWzY8LNzaBFhrrwK8pt/eost16-03.png\",\"https://cdn.steemitimages.com/DQmQ5YSnxdmJAaTqMtUXAuFWBshwfB1RvMYE9SUZav2NPZJ/eost16-04.png\",\"https://cdn.steemitimages.com/DQmVMjsmqijFFGQEn5p6hvZ1WJJsoprExhiXrw5u6q1JU9s/eost16-05.png\",\"https://cdn.steemitimages.com/DQmX5BFaZFWx2Qp7tnXM8w5LvyLc651yHM9xz6KYrvepTUh/eost16-06.png\",\"https://cdn.steemitimages.com/DQmcd2uS3b3HXa33pHjWjFxyFbTgc5Vabk9Dwvc9MyTc7Pt/eost16-07.png\",\"https://cdn.steemitimages.com/DQmdoBAfuadU6LpVLD7ZSobs8RUnNbUBxGzZQfYEbWKL7oS/eost16-08.png\",\"https://cdn.steemitimages.com/DQmRixG4GNd7rB5zUjLRtQa2ksNyfyTApA95sS9gjZg81hK/eost16-09.png\",\"https://cdn.steemitimages.com/DQmTVV6ErrYSAotJxjqWcRv8hkLTobvJL4ZMkYnAkA5ekQQ/eost16-10.png\",\"https://cdn.steemitimages.com/DQmVQ2sb1Fa7oE1AMBZVb3Bb6WKobnvKDZzbECUc2LnvHhN/eost16-11.png\",\"https://cdn.steemitimages.com/DQmXM1PBrQMNeLzQXbAe2779kALrKWsEvvBqSRb8tZMfpLd/eost16-12.png\",\"https://cdn.steemitimages.com/DQmWbY1mXGDZXE3gFyvCDC1e6LdwAN1gwv7qcEz8C7jpEgt/eost16-13.png\",\"https://cdn.steemitimages.com/DQmP3zFmiG9dw6EwgkYWgyKQUZsq7uUhe317mtDw754yQMh/eost16-14.png\",\"https://cdn.steemitimages.com/DQmXJU4CTjdZMZZPPCgeCUHCjm2DYS7oxJsUuPxrrS2HKYW/eost16-15.png\",\"https://cdn.steemitimages.com/DQmafMoqcsy7ZjnPXj8cfnsd4PQb4fEk89Cic221QAXXEXm/eost16-16.png\",\"https://cdn.steemitimages.com/DQmYzRQUvjK2cZjYSxoapVh7jaQzBo6wB7EwpQkhqvHgL3E/eost16-17.png\",\"https://cdn.steemitimages.com/DQmfZkU1udMk1QwnboiU8wBLnp1J22Z4a5jw9iXTRA6u8A9/eost16-18.png\",\"https://cdn.steemitimages.com/DQmZPZSSvqG2ZZUgg83Vf8KdCDzB9BTtjtWrQHi66NzsPNt/eost16-19.png\",\"https://cdn.steemitimages.com/DQmQMpQDAz26JxA15ttTvAUqdToV7zcbAQjnpTe4tXoBT1X/eost16-20.png\",\"https://cdn.steemitimages.com/DQmNwLnB4PGhzdvjqJmfPzzfrg7NM47SK1grz8TWDTFKFP5/eost16-21.png\",\"https://cdn.steemitimages.com/DQmWPfSJL5UzU4PQnUmR8v17PcxYvfWEqD8p5MhMbL8WwS5/eost16-22.png\",\"https://cdn.steemitimages.com/DQmbHPjuXGnFunwyC1m65WeX6YLcp3atuViWiXdaACpR7An/eost16-23.png\",\"https://cdn.steemitimages.com/DQmfVhbybw8q81CKEMVcMp55QRxMh1iy4V4UHntRC3eH8QR/eost16-24.png\",\"https://cdn.steemitimages.com/DQmbj2LbaKbjozfKqyvmX8LoRXWu8XN58KaRdhBf57nKBCv/eost16-25.png\"],\"links\":[\"http://eosfactory.io/build/html/tutorials/02.InteractingWithEOSContractsInEOSFactory.html\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2019/01/18 07:40:06
parent authoreoswing
parent permlinkeos-windows10-eosfactory
authorpartiko
permlinkpartiko-re-eoswing-eos-windows10-eosfactory-20190118t074006251z
title
body[![](https://d1vof77qrk4l5q.cloudfront.net/statics/upsell-delegate-15-steem-power-2.png)](https://partiko-io.app.link/A27hLeUkgT)
json metadata{"app":"partiko"}
Transaction InfoBlock #29557507/Trx d6d87a7442c980d95627d667645b8c135ca0afa4
View Raw JSON Data
{
  "trx_id": "d6d87a7442c980d95627d667645b8c135ca0afa4",
  "block": 29557507,
  "trx_in_block": 12,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-18T07:40:06",
  "op": [
    "comment",
    {
      "parent_author": "eoswing",
      "parent_permlink": "eos-windows10-eosfactory",
      "author": "partiko",
      "permlink": "partiko-re-eoswing-eos-windows10-eosfactory-20190118t074006251z",
      "title": "",
      "body": "[![](https://d1vof77qrk4l5q.cloudfront.net/statics/upsell-delegate-15-steem-power-2.png)](https://partiko-io.app.link/A27hLeUkgT)",
      "json_metadata": "{\"app\":\"partiko\"}"
    }
  ]
}
allazsent 0.001 STEEM to @eoswing- "Promote your post. Your post will be min. 10 resteemed with over 13000 followers and min. 25 Upvote Different account. Your post will be more popular and you will find new friends. Send 0.5 SBD or ..."
2019/01/16 09:12:21
fromallaz
toeoswing
amount0.001 STEEM
memoPromote your post. Your post will be min. 10 resteemed with over 13000 followers and min. 25 Upvote Different account. Your post will be more popular and you will find new friends. Send 0.5 SBD or STEEM to @allaz (post URL as memo ) Service Active.
Transaction InfoBlock #29501805/Trx 93603ce5715175ed15a97329edde4fa12abd3008
View Raw JSON Data
{
  "trx_id": "93603ce5715175ed15a97329edde4fa12abd3008",
  "block": 29501805,
  "trx_in_block": 11,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-16T09:12:21",
  "op": [
    "transfer",
    {
      "from": "allaz",
      "to": "eoswing",
      "amount": "0.001 STEEM",
      "memo": "Promote your post. Your post will be min. 10  resteemed with over 13000  followers and min. 25  Upvote Different account. Your post will be more popular and you will find new friends. Send 0.5 SBD or STEEM to @allaz (post URL as memo ) Service Active."
    }
  ]
}
eoswingpublished a new post: eos-windows10-eosfactory
2019/01/16 09:10:57
parent author
parent permlinkeos
authoreoswing
permlinkeos-windows10-eosfactory
title手把手教你玩eos:配置windows10下的EOSFactory开发测试框架
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![手把手-公众号.png](https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十五篇。本篇教程讲解如何在windows10中安装配置EOSFactory开发测试框架。 0.2 学习内容 相关概念 在WSL中配置EOS环境 安装EOSFactory 0.3 机器环境 笔记本电脑 操作系统:Windows 10 1 相关概念 1.1 技术配置栈 主要是依托windows10的WSL功能,在其中安装运行ubuntu作为EOS的测试环境,安装eosio.cdt开发包,采用EOSFactory开发测试框架。 1.2 WSL WSL全称Windows Subsystem for Linux,是一个为在Windows 10上能够原生运行Linux二进制可执行文件(ELF格式)的兼容层。通俗来讲是在Windows10 嵌入了个Linux子系统,方便运行大部分Linux 命令及软件。我们的windows10下EOS开发环境,很大部分就运行在WSL里面。 1.3 eosio.cdt EOSIO.CDT是WebAssembly(WASM)的工具链和一组工具,用于EOSIO平台的智能合约编译。 1.4 EOSFactory EOSFactory是由Tokenika创建的基于Python3的EOS智能合约开发和测试框架。目标是实现与以太坊Truffle框架类似的功能。 EOSFactory将EOS智能合约开发中一些繁琐枯燥工作简化。通过脚本自动化执行:编译智能合约,创建新的测试网络,部署合同,调用其方法并验证响应,然后撤除测试网络,最后报告结果等等。 EOSFactory由两层组成: ●C++客户端(即cleos)连接到EOS节点(即nodeos)运行私有或公共testnet, ●Python包装器充当操作调用接口。 2 在WSL中配置EOS环境 2.1 启用WSL功能 在 命令行界面 输入winver,查看windows10版本,确保在1803以上。 ![1.png](https://cdn.steemitimages.com/DQmauA1qroA7BCkHfbJPGymTte2tndKJkRDkbX8MTAfhfmX/1.png) 在 控制面板 中打开 “启用或关闭 Windows 功能” ,然后滚动至底部,如截图所示,勾选 “适用于 Linux 的 Windows 子系统”,点击确定。它将会下载安装需要的包。 ![2.png](https://cdn.steemitimages.com/DQmbZdAbttJQwoMM1kzDvW6EDwCnpvruna4GMETnrS9Wnic/2.png) 然后,重启windows10系统。 2.2 安装Ubuntu18.04 在Microsoft Store中搜索ubuntu,安装Ubuntu 18.04 LTS。 ![3.png](https://cdn.steemitimages.com/DQmb6cLLnwakWKrAjbM5gVou91n8CdRbYXnrUGRbeLkQcQv/3.png) 安装完成后,在开始菜单就可以找到ubuntu。 ![4.png](https://cdn.steemitimages.com/DQmRFzkRGED6m5GVZuHQGJBsQtiWnRkzQ4yd2yNMGTZRdHJ/4.png) 2.3 安装EOSIO 在硬盘空间较大的盘符下设置工作目录。这里我新建了F:/EOS文件夹。 打开Ubuntu,进入命令行终端。 首先进入工作目录: cd /mnt/f/EOS 然后,在github上查看最新版本https://github.com/EOSIO/eos/releases。 目前最新发行版是1.5.2。 新建一个tools目录,下载到本地。 mkdir tools cd tools wget https://github.com/EOSIO/eos/releases/download/v1.5.2/eosio_1.5.2-1-ubuntu-18.04_amd64.deb ![5.png](https://cdn.steemitimages.com/DQmeVEZUfAqCLit4MWnmVmW4f4kocduyCKwxXEbBis9tv37/5.png) 安装依赖项 sudo apt-get update wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - sudo apt-get install clang-4.0 lldb-4.0 libclang-4.0-dev cmake make libbz2-dev libssl-dev libgmp3-dev autotools-dev build-essential libbz2-dev libicu-dev python-dev autoconf libtool git mongodb sudo apt-get install libstdc++6 编译安装openssl 1.1版本 去官网下載: https://www.openssl.org/source/ ,我下载的是 openssl-1.1.0j.tar.gz 這個版本。 解压 tar -zxvf openssl-1.1.0j.tar.gz 编译安装 cd openssl-1.1.0j ./config --prefix=/usr/local/ssl shared zlib make depend make && make install 添加软链接 sudo ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1 sudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1 更新ubuntu环境 sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get upgrade sudo apt-get dist-upgrade 安装EOSIO sudo apt install ./eosio_1.5.2-1-ubuntu-18.04_amd64.deb 验证下安装情况 cleos --help ![6.png](https://cdn.steemitimages.com/DQmZxrUnzqFXFpyS3N9xXYmRPfdpHeUddDnNwPZfmHUZgw4/6.png) nodeos --help ![7.png](https://cdn.steemitimages.com/DQmZXVZUa6GmrXcidWk4PNTMCi991Kt3Qr7hrisYXPtpQiE/7.png) keosd --help ![8.png](https://cdn.steemitimages.com/DQmUdsvxuiERCgqoexsQ2EQnHQTcyPb1UCjQLKKQy3H7Lph/8.png) 2.4 安装eosio.cdt cd /mnt/f/EOS/tools wget https://github.com/eosio/eosio.cdt/releases/download/v1.4.1/eosio.cdt-1.4.1.x86_64.deb sudo apt install ./eosio.cdt-1.4.1.x86_64.deb 3 安装EOSFactory 3.1 配置Python3环境 通常来说,ubuntu18.04里是有python3的,但是没有pip3。 查看python3 python3 --version ![9.png](https://cdn.steemitimages.com/DQmQmxoApBsgdB2hMnHTanC5FfWxRAoSnDKMf66Ct2QsVy3/9.png) 安装python3的pip。 sudo apt-get install python3-pip pip3 install --upgrade pip 此时如果输入 pip3 –version 提示错误大致为:cannot import name ‘main’。 还需要修改/usr/bin/pip3文件。 sudo vim /usr/bin/pip3 打开文件,并将文件修改为 from pip import __main__ if __name__ == '__main__': sys.exit(__main__._main()) 修改后,/usr/bin/pip3文件如下图所示: ![10.png](https://cdn.steemitimages.com/DQmQyjno1HnrcAEWTc42RJbChSUyZGeDGroBJUqygp69nzD/10.png) 保存退出后即可完成pip3的更新。 再次查看: ![11.png](https://cdn.steemitimages.com/DQmWK3EXr5cWL7j8c1Zmfg5kW6hV6Js7npX4Tpdj4Mwvfwn/11.png) 3.2 安装EOSFactory 从github下载代码 cd /mnt/f/EOS git clone https://github.com/tokenika/eosfactory.git ![12.png](https://cdn.steemitimages.com/DQmYdu2kS8nqTj9Rkq8rjJ2i9pWZniAULX9Xcj2DQgCFDA8/12.png) 创建contracts文件夹 mkdir contracts 安装EOSFactory cd eosfactory ./install.sh ![13.png](https://cdn.steemitimages.com/DQmXC3oNHYkCExau9NRUXG9gNdbAXi5EZ1zYwRz1vUegemm/13.png) 中间遇到提示时,输入contreacts文件夹的地址。 ![14.png](https://cdn.steemitimages.com/DQmSQCwwtTZpPbwbnFJLch7feWgESQdRXK8BZvmbjr22sAA/14.png) 3.3 执行测试脚本 运行测试脚本01_hello_world.py python3 tests/01_hello_world.py ![15.png](https://cdn.steemitimages.com/DQmVZkC8aG9V8GLQJVfAcxkeVQq5pVKa8UqnzpKUWXMWvJx/15.png) ![16.png](https://cdn.steemitimages.com/DQmaVXRXw5SjQG7Bs6R9GmpNpeYYjcBEGc5gaYDYfFYWNRY/16.png) 运行测试脚本02_eosio_token.py python3 tests/02_eosio_token.py ![17.png](https://cdn.steemitimages.com/DQmcENDZo95Hv99McrBYRw8m9Z6wePTTK83VTP5ASUm32CG/17.png) ![18.png](https://cdn.steemitimages.com/DQmUf2rejvSS4bKHxMJAjhtaapNz9zx8mFpzGUttNNTuwz9/18.png) 运行测试脚本03_tic_tac_toe.py python3 tests/03_tic_tac_toe.py ![19.png](https://cdn.steemitimages.com/DQmcPHUTUTtiHZATKtUxCka3ixjQFHBV4csqjXaiu6tVm4d/19.png) ![20.png](https://cdn.steemitimages.com/DQmNbiRuWSSXDTY7byQqKyMw3mcYhdUnU5fwV1cRj2hUBx8/20.png) 至此,在windows10系统下的EOSfactory开发测试框架就安装完成了。 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: ●安装EOSFactory: http://eosfactory.io/build/html/tutorials/01.InstallingEOSFactory.html 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png","https://cdn.steemitimages.com/DQmauA1qroA7BCkHfbJPGymTte2tndKJkRDkbX8MTAfhfmX/1.png","https://cdn.steemitimages.com/DQmbZdAbttJQwoMM1kzDvW6EDwCnpvruna4GMETnrS9Wnic/2.png","https://cdn.steemitimages.com/DQmb6cLLnwakWKrAjbM5gVou91n8CdRbYXnrUGRbeLkQcQv/3.png","https://cdn.steemitimages.com/DQmRFzkRGED6m5GVZuHQGJBsQtiWnRkzQ4yd2yNMGTZRdHJ/4.png","https://cdn.steemitimages.com/DQmeVEZUfAqCLit4MWnmVmW4f4kocduyCKwxXEbBis9tv37/5.png","https://cdn.steemitimages.com/DQmZxrUnzqFXFpyS3N9xXYmRPfdpHeUddDnNwPZfmHUZgw4/6.png","https://cdn.steemitimages.com/DQmZXVZUa6GmrXcidWk4PNTMCi991Kt3Qr7hrisYXPtpQiE/7.png","https://cdn.steemitimages.com/DQmUdsvxuiERCgqoexsQ2EQnHQTcyPb1UCjQLKKQy3H7Lph/8.png","https://cdn.steemitimages.com/DQmQmxoApBsgdB2hMnHTanC5FfWxRAoSnDKMf66Ct2QsVy3/9.png","https://cdn.steemitimages.com/DQmQyjno1HnrcAEWTc42RJbChSUyZGeDGroBJUqygp69nzD/10.png","https://cdn.steemitimages.com/DQmWK3EXr5cWL7j8c1Zmfg5kW6hV6Js7npX4Tpdj4Mwvfwn/11.png","https://cdn.steemitimages.com/DQmYdu2kS8nqTj9Rkq8rjJ2i9pWZniAULX9Xcj2DQgCFDA8/12.png","https://cdn.steemitimages.com/DQmXC3oNHYkCExau9NRUXG9gNdbAXi5EZ1zYwRz1vUegemm/13.png","https://cdn.steemitimages.com/DQmSQCwwtTZpPbwbnFJLch7feWgESQdRXK8BZvmbjr22sAA/14.png","https://cdn.steemitimages.com/DQmVZkC8aG9V8GLQJVfAcxkeVQq5pVKa8UqnzpKUWXMWvJx/15.png","https://cdn.steemitimages.com/DQmaVXRXw5SjQG7Bs6R9GmpNpeYYjcBEGc5gaYDYfFYWNRY/16.png","https://cdn.steemitimages.com/DQmcENDZo95Hv99McrBYRw8m9Z6wePTTK83VTP5ASUm32CG/17.png","https://cdn.steemitimages.com/DQmUf2rejvSS4bKHxMJAjhtaapNz9zx8mFpzGUttNNTuwz9/18.png","https://cdn.steemitimages.com/DQmcPHUTUTtiHZATKtUxCka3ixjQFHBV4csqjXaiu6tVm4d/19.png","https://cdn.steemitimages.com/DQmNbiRuWSSXDTY7byQqKyMw3mcYhdUnU5fwV1cRj2hUBx8/20.png"],"links":["https://github.com/EOSIO/eos/releases。","https://github.com/EOSIO/eos/releases/download/v1.5.2/eosio_1.5.2-1-ubuntu-18.04_amd64.deb","https://apt.llvm.org/llvm-snapshot.gpg.key|sudo","https://www.openssl.org/source/","https://github.com/eosio/eosio.cdt/releases/download/v1.4.1/eosio.cdt-1.4.1.x86_64.deb","https://github.com/tokenika/eosfactory.git","http://eosfactory.io/build/html/tutorials/01.InstallingEOSFactory.html"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #29501777/Trx ac0cedcadde06f04aa1facefdbbeceb0b8087c6b
View Raw JSON Data
{
  "trx_id": "ac0cedcadde06f04aa1facefdbbeceb0b8087c6b",
  "block": 29501777,
  "trx_in_block": 12,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-16T09:10:57",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-windows10-eosfactory",
      "title": "手把手教你玩eos:配置windows10下的EOSFactory开发测试框架",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![手把手-公众号.png](https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十五篇。本篇教程讲解如何在windows10中安装配置EOSFactory开发测试框架。\n\n0.2 学习内容\n相关概念\n在WSL中配置EOS环境\n安装EOSFactory\n\n0.3 机器环境\n笔记本电脑\n操作系统:Windows 10\n\n1 相关概念\n1.1 技术配置栈\n主要是依托windows10的WSL功能,在其中安装运行ubuntu作为EOS的测试环境,安装eosio.cdt开发包,采用EOSFactory开发测试框架。\n\n1.2 WSL\nWSL全称Windows Subsystem for Linux,是一个为在Windows 10上能够原生运行Linux二进制可执行文件(ELF格式)的兼容层。通俗来讲是在Windows10 嵌入了个Linux子系统,方便运行大部分Linux 命令及软件。我们的windows10下EOS开发环境,很大部分就运行在WSL里面。\n\n1.3 eosio.cdt\nEOSIO.CDT是WebAssembly(WASM)的工具链和一组工具,用于EOSIO平台的智能合约编译。\n\n1.4 EOSFactory\nEOSFactory是由Tokenika创建的基于Python3的EOS智能合约开发和测试框架。目标是实现与以太坊Truffle框架类似的功能。\nEOSFactory将EOS智能合约开发中一些繁琐枯燥工作简化。通过脚本自动化执行:编译智能合约,创建新的测试网络,部署合同,调用其方法并验证响应,然后撤除测试网络,最后报告结果等等。\nEOSFactory由两层组成:\n●C++客户端(即cleos)连接到EOS节点(即nodeos)运行私有或公共testnet,\n●Python包装器充当操作调用接口。\n\n2 在WSL中配置EOS环境\n2.1 启用WSL功能\n在 命令行界面 输入winver,查看windows10版本,确保在1803以上。\n![1.png](https://cdn.steemitimages.com/DQmauA1qroA7BCkHfbJPGymTte2tndKJkRDkbX8MTAfhfmX/1.png)\n在 控制面板 中打开 “启用或关闭 Windows 功能” ,然后滚动至底部,如截图所示,勾选 “适用于 Linux 的 Windows 子系统”,点击确定。它将会下载安装需要的包。\n![2.png](https://cdn.steemitimages.com/DQmbZdAbttJQwoMM1kzDvW6EDwCnpvruna4GMETnrS9Wnic/2.png)\n然后,重启windows10系统。\n\n2.2 安装Ubuntu18.04\n在Microsoft Store中搜索ubuntu,安装Ubuntu 18.04 LTS。\n![3.png](https://cdn.steemitimages.com/DQmb6cLLnwakWKrAjbM5gVou91n8CdRbYXnrUGRbeLkQcQv/3.png)\n安装完成后,在开始菜单就可以找到ubuntu。\n![4.png](https://cdn.steemitimages.com/DQmRFzkRGED6m5GVZuHQGJBsQtiWnRkzQ4yd2yNMGTZRdHJ/4.png)\n\n2.3 安装EOSIO\n在硬盘空间较大的盘符下设置工作目录。这里我新建了F:/EOS文件夹。\n打开Ubuntu,进入命令行终端。\n首先进入工作目录:\ncd /mnt/f/EOS\n然后,在github上查看最新版本https://github.com/EOSIO/eos/releases。\n目前最新发行版是1.5.2。\n新建一个tools目录,下载到本地。\nmkdir tools\ncd tools\nwget https://github.com/EOSIO/eos/releases/download/v1.5.2/eosio_1.5.2-1-ubuntu-18.04_amd64.deb\n![5.png](https://cdn.steemitimages.com/DQmeVEZUfAqCLit4MWnmVmW4f4kocduyCKwxXEbBis9tv37/5.png)\n安装依赖项\nsudo apt-get update\nwget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -\nsudo apt-get install clang-4.0 lldb-4.0 libclang-4.0-dev cmake make libbz2-dev libssl-dev libgmp3-dev autotools-dev build-essential libbz2-dev libicu-dev python-dev autoconf libtool git mongodb\nsudo apt-get install libstdc++6\n编译安装openssl 1.1版本\n去官网下載: https://www.openssl.org/source/ ,我下载的是 openssl-1.1.0j.tar.gz 這個版本。\n解压\ntar -zxvf openssl-1.1.0j.tar.gz\t\n编译安装\ncd openssl-1.1.0j\n./config --prefix=/usr/local/ssl shared zlib\n\tmake depend \n\tmake && make install\n添加软链接\nsudo ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1\nsudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1\n更新ubuntu环境\nsudo add-apt-repository ppa:ubuntu-toolchain-r/test\nsudo apt-get update\nsudo apt-get upgrade\nsudo apt-get dist-upgrade\n安装EOSIO\nsudo apt install ./eosio_1.5.2-1-ubuntu-18.04_amd64.deb\n验证下安装情况\ncleos --help\n![6.png](https://cdn.steemitimages.com/DQmZxrUnzqFXFpyS3N9xXYmRPfdpHeUddDnNwPZfmHUZgw4/6.png)\nnodeos --help\n![7.png](https://cdn.steemitimages.com/DQmZXVZUa6GmrXcidWk4PNTMCi991Kt3Qr7hrisYXPtpQiE/7.png)\nkeosd --help\n![8.png](https://cdn.steemitimages.com/DQmUdsvxuiERCgqoexsQ2EQnHQTcyPb1UCjQLKKQy3H7Lph/8.png)\n\n2.4 安装eosio.cdt\ncd /mnt/f/EOS/tools\nwget https://github.com/eosio/eosio.cdt/releases/download/v1.4.1/eosio.cdt-1.4.1.x86_64.deb\n\nsudo apt install ./eosio.cdt-1.4.1.x86_64.deb\n\n3 安装EOSFactory\n3.1 配置Python3环境\n通常来说,ubuntu18.04里是有python3的,但是没有pip3。\n查看python3\npython3 --version\n![9.png](https://cdn.steemitimages.com/DQmQmxoApBsgdB2hMnHTanC5FfWxRAoSnDKMf66Ct2QsVy3/9.png)\n安装python3的pip。\nsudo apt-get install python3-pip\n\npip3 install --upgrade pip\n此时如果输入 pip3 –version\n提示错误大致为:cannot import name ‘main’。\n还需要修改/usr/bin/pip3文件。\nsudo vim /usr/bin/pip3 \n打开文件,并将文件修改为\nfrom pip import __main__\n\nif __name__ == '__main__':\n    \t\tsys.exit(__main__._main())\n修改后,/usr/bin/pip3文件如下图所示:\n![10.png](https://cdn.steemitimages.com/DQmQyjno1HnrcAEWTc42RJbChSUyZGeDGroBJUqygp69nzD/10.png)\n保存退出后即可完成pip3的更新。\n再次查看:\n![11.png](https://cdn.steemitimages.com/DQmWK3EXr5cWL7j8c1Zmfg5kW6hV6Js7npX4Tpdj4Mwvfwn/11.png)\n\n3.2 安装EOSFactory\n从github下载代码\ncd /mnt/f/EOS\ngit clone https://github.com/tokenika/eosfactory.git\n![12.png](https://cdn.steemitimages.com/DQmYdu2kS8nqTj9Rkq8rjJ2i9pWZniAULX9Xcj2DQgCFDA8/12.png)\n创建contracts文件夹\nmkdir contracts\n安装EOSFactory\ncd eosfactory\n./install.sh\n![13.png](https://cdn.steemitimages.com/DQmXC3oNHYkCExau9NRUXG9gNdbAXi5EZ1zYwRz1vUegemm/13.png)\n中间遇到提示时,输入contreacts文件夹的地址。\n![14.png](https://cdn.steemitimages.com/DQmSQCwwtTZpPbwbnFJLch7feWgESQdRXK8BZvmbjr22sAA/14.png)\n\n3.3 执行测试脚本\n运行测试脚本01_hello_world.py\npython3 tests/01_hello_world.py\n![15.png](https://cdn.steemitimages.com/DQmVZkC8aG9V8GLQJVfAcxkeVQq5pVKa8UqnzpKUWXMWvJx/15.png)\n![16.png](https://cdn.steemitimages.com/DQmaVXRXw5SjQG7Bs6R9GmpNpeYYjcBEGc5gaYDYfFYWNRY/16.png)\n运行测试脚本02_eosio_token.py\npython3 tests/02_eosio_token.py\n![17.png](https://cdn.steemitimages.com/DQmcENDZo95Hv99McrBYRw8m9Z6wePTTK83VTP5ASUm32CG/17.png)\n![18.png](https://cdn.steemitimages.com/DQmUf2rejvSS4bKHxMJAjhtaapNz9zx8mFpzGUttNNTuwz9/18.png)\n运行测试脚本03_tic_tac_toe.py\npython3 tests/03_tic_tac_toe.py\n![19.png](https://cdn.steemitimages.com/DQmcPHUTUTtiHZATKtUxCka3ixjQFHBV4csqjXaiu6tVm4d/19.png)\n![20.png](https://cdn.steemitimages.com/DQmNbiRuWSSXDTY7byQqKyMw3mcYhdUnU5fwV1cRj2hUBx8/20.png)\n至此,在windows10系统下的EOSfactory开发测试框架就安装完成了。\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n●安装EOSFactory: http://eosfactory.io/build/html/tutorials/01.InstallingEOSFactory.html\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmeZgpV3tnDoQju7hBFPh7zobBRDFysLsxqt8Bma2eNfeB/%E6%89%8B%E6%8A%8A%E6%89%8B-%E5%85%AC%E4%BC%97%E5%8F%B7.png\",\"https://cdn.steemitimages.com/DQmauA1qroA7BCkHfbJPGymTte2tndKJkRDkbX8MTAfhfmX/1.png\",\"https://cdn.steemitimages.com/DQmbZdAbttJQwoMM1kzDvW6EDwCnpvruna4GMETnrS9Wnic/2.png\",\"https://cdn.steemitimages.com/DQmb6cLLnwakWKrAjbM5gVou91n8CdRbYXnrUGRbeLkQcQv/3.png\",\"https://cdn.steemitimages.com/DQmRFzkRGED6m5GVZuHQGJBsQtiWnRkzQ4yd2yNMGTZRdHJ/4.png\",\"https://cdn.steemitimages.com/DQmeVEZUfAqCLit4MWnmVmW4f4kocduyCKwxXEbBis9tv37/5.png\",\"https://cdn.steemitimages.com/DQmZxrUnzqFXFpyS3N9xXYmRPfdpHeUddDnNwPZfmHUZgw4/6.png\",\"https://cdn.steemitimages.com/DQmZXVZUa6GmrXcidWk4PNTMCi991Kt3Qr7hrisYXPtpQiE/7.png\",\"https://cdn.steemitimages.com/DQmUdsvxuiERCgqoexsQ2EQnHQTcyPb1UCjQLKKQy3H7Lph/8.png\",\"https://cdn.steemitimages.com/DQmQmxoApBsgdB2hMnHTanC5FfWxRAoSnDKMf66Ct2QsVy3/9.png\",\"https://cdn.steemitimages.com/DQmQyjno1HnrcAEWTc42RJbChSUyZGeDGroBJUqygp69nzD/10.png\",\"https://cdn.steemitimages.com/DQmWK3EXr5cWL7j8c1Zmfg5kW6hV6Js7npX4Tpdj4Mwvfwn/11.png\",\"https://cdn.steemitimages.com/DQmYdu2kS8nqTj9Rkq8rjJ2i9pWZniAULX9Xcj2DQgCFDA8/12.png\",\"https://cdn.steemitimages.com/DQmXC3oNHYkCExau9NRUXG9gNdbAXi5EZ1zYwRz1vUegemm/13.png\",\"https://cdn.steemitimages.com/DQmSQCwwtTZpPbwbnFJLch7feWgESQdRXK8BZvmbjr22sAA/14.png\",\"https://cdn.steemitimages.com/DQmVZkC8aG9V8GLQJVfAcxkeVQq5pVKa8UqnzpKUWXMWvJx/15.png\",\"https://cdn.steemitimages.com/DQmaVXRXw5SjQG7Bs6R9GmpNpeYYjcBEGc5gaYDYfFYWNRY/16.png\",\"https://cdn.steemitimages.com/DQmcENDZo95Hv99McrBYRw8m9Z6wePTTK83VTP5ASUm32CG/17.png\",\"https://cdn.steemitimages.com/DQmUf2rejvSS4bKHxMJAjhtaapNz9zx8mFpzGUttNNTuwz9/18.png\",\"https://cdn.steemitimages.com/DQmcPHUTUTtiHZATKtUxCka3ixjQFHBV4csqjXaiu6tVm4d/19.png\",\"https://cdn.steemitimages.com/DQmNbiRuWSSXDTY7byQqKyMw3mcYhdUnU5fwV1cRj2hUBx8/20.png\"],\"links\":[\"https://github.com/EOSIO/eos/releases。\",\"https://github.com/EOSIO/eos/releases/download/v1.5.2/eosio_1.5.2-1-ubuntu-18.04_amd64.deb\",\"https://apt.llvm.org/llvm-snapshot.gpg.key|sudo\",\"https://www.openssl.org/source/\",\"https://github.com/eosio/eosio.cdt/releases/download/v1.4.1/eosio.cdt-1.4.1.x86_64.deb\",\"https://github.com/tokenika/eosfactory.git\",\"http://eosfactory.io/build/html/tutorials/01.InstallingEOSFactory.html\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
filipinoupvoted (10.00%) @eoswing / 651hms-eos
2019/01/09 10:32:30
voterfilipino
authoreoswing
permlink651hms-eos
weight1000 (10.00%)
Transaction InfoBlock #29301972/Trx b673fa1758995bdfeb7b307989dfbef01077ba44
View Raw JSON Data
{
  "trx_id": "b673fa1758995bdfeb7b307989dfbef01077ba44",
  "block": 29301972,
  "trx_in_block": 3,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T10:32:30",
  "op": [
    "vote",
    {
      "voter": "filipino",
      "author": "eoswing",
      "permlink": "651hms-eos",
      "weight": 1000
    }
  ]
}
2019/01/09 10:11:39
voteracknowledgement
authoreoswing
permlink651hms-eos
weight1000 (10.00%)
Transaction InfoBlock #29301555/Trx 85bb74818b77eee2b93c5fda3ae817dc42d2c3cd
View Raw JSON Data
{
  "trx_id": "85bb74818b77eee2b93c5fda3ae817dc42d2c3cd",
  "block": 29301555,
  "trx_in_block": 5,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T10:11:39",
  "op": [
    "vote",
    {
      "voter": "acknowledgement",
      "author": "eoswing",
      "permlink": "651hms-eos",
      "weight": 1000
    }
  ]
}
fyrstikkenupvoted (1.00%) @eoswing / 651hms-eos
2019/01/09 10:03:45
voterfyrstikken
authoreoswing
permlink651hms-eos
weight100 (1.00%)
Transaction InfoBlock #29301397/Trx 02d4b347e9964414e655056cdb5aca6607c6b517
View Raw JSON Data
{
  "trx_id": "02d4b347e9964414e655056cdb5aca6607c6b517",
  "block": 29301397,
  "trx_in_block": 10,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T10:03:45",
  "op": [
    "vote",
    {
      "voter": "fyrstikken",
      "author": "eoswing",
      "permlink": "651hms-eos",
      "weight": 100
    }
  ]
}
pinoyupvoted (100.00%) @eoswing / 651hms-eos
2019/01/09 10:02:15
voterpinoy
authoreoswing
permlink651hms-eos
weight10000 (100.00%)
Transaction InfoBlock #29301367/Trx df719d209485d1333d75f462f1e7cbb98872e7c4
View Raw JSON Data
{
  "trx_id": "df719d209485d1333d75f462f1e7cbb98872e7c4",
  "block": 29301367,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T10:02:15",
  "op": [
    "vote",
    {
      "voter": "pinoy",
      "author": "eoswing",
      "permlink": "651hms-eos",
      "weight": 10000
    }
  ]
}
sasha3242upvoted (100.00%) @eoswing / 651hms-eos
2019/01/09 09:47:15
votersasha3242
authoreoswing
permlink651hms-eos
weight10000 (100.00%)
Transaction InfoBlock #29301067/Trx 0f7e935a9d4f48718ea105afecc61843be290138
View Raw JSON Data
{
  "trx_id": "0f7e935a9d4f48718ea105afecc61843be290138",
  "block": 29301067,
  "trx_in_block": 8,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T09:47:15",
  "op": [
    "vote",
    {
      "voter": "sasha3242",
      "author": "eoswing",
      "permlink": "651hms-eos",
      "weight": 10000
    }
  ]
}
eoswingpublished a new post: 651hms-eos
2019/01/09 09:46:42
parent author
parent permlinkeos
authoreoswing
permlink651hms-eos
title手把手教你玩eos:卡牌游戏第八课——优化细节体验
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十四篇。本篇教程是卡牌游戏的最后一课,讲解怎么进一步优化整个游戏的细节体验。 0.2 学习内容 相关准备 编写前端代码 测试代码 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 在本课程中,我们将优化游戏细节体验,比如添加游戏帮助对话框,进度提示,优化加载体验等等。 1.2 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入前端文件夹 cd /eos-work/frontend/ 2 编写前端代码 2.1 添加游戏帮助对话框 在GameInfo中添加RulesModal模态对话框 cd ./src/components/Game/components/GameInfo svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-8/frontend/src/components/Game/components/GameInfo/components 在GameInfo.jsx中加入RulesModal组件 vi GameInfo.jsx 更新代码如下: import React, { Component } from 'react'; // Components import { Button } from 'components'; //在此次添加引用 // Game subcomponents import { RulesModal } from './components'; class Info extends Component { render() { // Extract data and event functions from props const { className, deckCardCount, handCardCount, onEndGame } = this.props; // Display: // Round number: 18 <-- ((max deck = 17) + 1) - Deck Cards - Hand Cards // Rules button to trigger a modal // Button to end the current game return ( <div className={`Info${ className ? ' ' + className : '' }`}> { <p>ROUND className="round-number">`{ 18 - deckCardCount - handCardCount }/17 </p> } //在此处添加组件 <div><Button onClick={ onEndGame } className="small red">QUIT</Button></div> </div> ) } } export default Info; 2.2 添加进度提示 cd /eos-work/frontend/src/components/Button/ vi Button.jsx 编辑代码如下: import React, { Component } from 'react'; class Button extends Component { constructor(props) { // Inherit constructor super(props); // Component state setup this.state = { loading: false, }; // Bind functions this.handleClick = this.handleClick.bind(this); } handleClick() { const { onClick } = this.props; // Show the loading indicator in case the action to be performed takes too long this.setState({ loading: true }); // If the prop onClick is a function, invoke it and stores its return value in ``promise`` // If the prop onClick is NOT a function, the value of ``promise`` will be false const promise = typeof onClick === "function" && onClick(); // If ``promise`` is a function (a Promise), invoke setState after it has been resolved. if (promise && typeof promise.then === "function") { return promise.then(() => { this.isComponentMounted && this.setState({ loading: false }); }); } // Otherwise, just invoke setState directly this.isComponentMounted && this.setState({ loading: false }); } componentDidMount() { this.isComponentMounted = true; } componentWillUnmount() { this.isComponentMounted = false; } render() { const { className, type, style, children } = this.props; let { loading } = this.state; // Enable the loading CSS class if either the private state attribute `loading` // or the props `loading` is true loading = loading || this.props.loading; return ( <button className={`Button${ className ? ' ' + className : '' }${ loading ? ' loading' : '' }`} onClick={ this.handleClick } { ...{ type, style } } >{ children }</button> ); } } export default Button; 在Game.jsx中更新引用 cd /eos-work/frontend/src/components/Game/ vi Game.jsx 编辑代码如下: // React core import React, { Component } from 'react'; import { connect } from 'react-redux'; // Game subcomponents import { GameInfo, GameMat, PlayerProfile, Resolution } from './components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class Game extends Component { constructor(props) { // Inherit constructor super(props); // State for showing/hiding components when the API (blockchain) request is loading this.state = { loading: true, }; // Bind functions this.loadUser = this.loadUser.bind(this); this.handleStartGame = this.handleStartGame.bind(this); this.handlePlayCard = this.handlePlayCard.bind(this); this.handleNextRound = this.handleNextRound.bind(this); this.handleEndGame = this.handleEndGame.bind(this); // Call `loadUser` before mounting the app this.loadUser(); } // Get latest user object from blockchain loadUser() { // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux const { setUser, user: { name } } = this.props; // Send request the blockchain by calling the ApiService, // Get the user object and store the `win_count`, `lost_count` and `game_data` object return ApiService.getUserByName(name).then(user => { setUser({ win_count: user.win_count, lost_count: user.lost_count, game: user.game_data, }); // Set the loading state to false for displaying the app this.setState({ loading: false }); }); } handleStartGame() { // Send a request to API (blockchain) to start game // And call `loadUser` again for react to render latest game status to UI return ApiService.startGame().then(()=>{ return this.loadUser(); }); } handlePlayCard(cardIdx) { // Extract `user.game` of `UserReducer` from redux const { user: { game } } = this.props; // If it is an empty card, not going to do anything if (game.hand_player[cardIdx] === 0) { return; } // Show the loading indicator if the connection took too long this.setState({ loading: true }); // Send a request to API (blockchain) to play card with card index // And call `loadUser` again for react to render latest game status to UI return ApiService.playCard(cardIdx).then(()=>{ return this.loadUser(); }); } handleNextRound() { // Send a request to API (blockchain) to trigger next round // And call `loadUser` again for react to render latest game status to UI return ApiService.nextRound().then(()=>{ return this.loadUser(); }); } handleEndGame() { // Send a request to API (blockchain) to end the game // And call `loadUser` again for react to render latest game status to UI return ApiService.endGame().then(()=>{ return this.loadUser(); }); } render() { // Extract data from state and user data of `UserReducer` from redux const { loading } = this.state; const { user: { name, win_count, lost_count, game } } = this.props; // Flag to indicate if the game has started or not // By checking if the deckCard of AI is still 17 (max card) const isGameStarted = game && game.deck_ai.length !== 17; // If game hasn't started, display `PlayerProfile` // If game has started, display `GameMat`, `Resolution`, `Info` screen return ( <section className={`Game${ (loading ? " loading" : "") }`}> { !isGameStarted ? <PlayerProfile name={ name } winCount={ win_count } lostCount={ lost_count } onLogout={ this.handleLogout } onStartGame={ this.handleStartGame } /> : <div className="container"> <GameMat deckCardCount={ game.deck_ai.length } aiLife={ game.life_ai } aiHandCards={ game.hand_ai } aiName="COMPUTER" playerLife={ game.life_player } playerHandCards={ game.hand_player } playerName={ name } onPlayCard={ this.handlePlayCard } /> <Resolution status={ game.status } aiCard={ game.selected_card_ai } aiName="COMPUTER" aiLost={ game.life_lost_ai } playerCard={ game.selected_card_player } playerName={ name } playerLost={ game.life_lost_player } onNextRound={ this.handleNextRound } onEndGame={ this.handleEndGame } /> <GameInfo deckCardCount={ game.deck_ai.length } handCardCount={ game.hand_ai.filter( x => x > 0 ).length } onEndGame={ this.handleEndGame } /> </div> } { isGameStarted && loading && <div className="spinner"> <div className="image"></div> <div className="circles"> <div className="circle"> <div className="inner"></div> </div> <div className="circle"> <div className="inner"></div> </div> <div className="circle"> <div className="inner"></div> </div> <div className="circle"> <div className="inner"></div> </div> <div className="circle"> <div className="inner"></div> </div> </div> </div> } </section> ) } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(Game); 2.3 优化加载体验 现在每次刷新游戏屏幕时都会短暂显示登录屏幕。 这是由ApiService从区块链获取最新用户数据引起的。 在检索用户数据时,dApp认为用户没有登录。 为了防止这种情况,我们将向App.jsx添加一个名为loading的组件状态。 在检索区块链数据时出现,直到有反馈,确定是应用是在登录页面,游戏结束屏幕还是个人资料屏幕等等。 cd /eos-work/frontend/src/components/Login/ vi Login.jsx 更新代码如下: import React, { Component } from 'react'; import { connect } from 'react-redux'; // Components import { Button } from 'components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class Login extends Component { constructor(props) { // Inherit constructor super(props); // State for form data and error message this.state = { form: { username: '', key: '', error: '', }, isSigningIn: false, } // Bind functions this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } // Runs on every keystroke to update the React state handleChange(event) { const { name, value } = event.target; const { form } = this.state; this.setState({ form: { ...form, [name]: value, error: '', }, }); } componentDidMount() { this.isComponentMounted = true; } componentWillUnmount() { this.isComponentMounted = false; } // Handle form submission to call api handleSubmit(event) { // Stop the default form submit browser behaviour event.preventDefault(); // Extract `form` state const { form } = this.state; // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux const { setUser } = this.props; // Set loading spinner to the button this.setState({ isSigningIn: true }); // Send a login transaction to the blockchain by calling the ApiService, // If it successes, save the username to redux store // Otherwise, save the error state for displaying the message return ApiService.login(form) .then(() => { setUser({ name: form.username }); }) .catch(err => { this.setState({ error: err.toString() }); }) .finally(() => { if (this.isComponentMounted) { this.setState({ isSigningIn: false }); } }); } render() { // Extract data from state const { form, error, isSigningIn } = this.state; return ( <div className="Login"> <div className="title">Elemental Battles - powered by EOSIO</div> <div className="description">Please use the Account Name and Private Key generated in the previous page to log into the game.</div> <form name="form" onSubmit={ this.handleSubmit }> <div className="field"> Account name <input type="text" name="username" value={ form.username } placeholder="All small letters, a-z, 1-5 or dot, max 12 characters" onChange={ this.handleChange } pattern="[\.a-z1-5]{2,12}" required /> </div> <div className="field"> Private key <input type="password" name="key" value={ form.key } onChange={ this.handleChange } pattern="^.{51,}$" required /> </div> <div className="field form-error"> { error && < className="error"> { error } > } </div> <div className="bottom"> <Button type="submit" className="green" loading={ isSigningIn }> { "CONFIRM" } </Button> </div> </form> </div> ) } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(Login); 再在App.jsx中更新引用 cd /eos-work/frontend/src/components/App/ vi App.jsx 更新代码如下: // React core import React, { Component } from 'react'; import { connect } from 'react-redux'; // Components import { Game, Login } from 'components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class App extends Component { constructor(props) { // Inherit constructor super(props); // 此处添加状态,默认loading为true // State for showing/hiding components when the API (blockchain) request is loading this.state = { loading: true, }; // Bind functions this.getCurrentUser = this.getCurrentUser.bind(this); // Call getCurrentUser before mounting the app this.getCurrentUser(); } getCurrentUser() { // Extract setUser of UserAction from redux const { setUser } = this.props; // Send a request to API (blockchain) to get the current logged in user return ApiService.getCurrentUser() // If the server return a username .then(username => { // Save the username to redux store // For structure, ref: ./frontend/src/reducers/UserReducer.js setUser({ name: username }); }) // To ignore 401 console error .catch(() => {}) //在获取到区块链数据反馈后,设置loading状态为false // Run the following function no matter the server return success or error .finally(() => { // Set the loading state to false for displaying the app this.setState({ loading: false }); }); } render() { // Extract data from state and props (`user` is from redux) const { loading } = this.state; const { user: { name, game } } = this.props; // 确定游戏处于什么状态 // Determine the app status for styling let appStatus = "login"; if (game && game.status !== 0) { appStatus = "game-ended"; } else if (game && game.selected_card_ai > 0) { appStatus = "card-selected"; } else if (game && game.deck_ai.length !== 17) { appStatus = "started"; } else if (name) { appStatus = "profile"; } // Set class according to loading state, it will hide the app (ref to css file) // If the username is set in redux, display the Game component // If the username is NOT set in redux, display the Login component return ( <div className={ `App status-${ appStatus }${ loading ? " loading" : "" }` }> { name && } { !name && } </div> ); } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(App); 3 测试代码 cd /eos-work/frontend npm start 在浏览器中输入网址测试。 点击右边的rules按钮查看游戏规则帮助 ![eost14-01.png](https://cdn.steemitimages.com/DQmfGqPk1Vuomn3qYfPbaLdtKKuXCjHmoDdDhXGWzMNGSYy/eost14-01.png) 选择卡牌后,在等待时会出现进度加载提示: ![eost14-02.png](https://cdn.steemitimages.com/DQmWJVovkJci4CRjXnyPc7pFW9e1ALamf251VLFdA92kcmA/eost14-02.png) 还有刷新后回到主界面等等,就不一一截图了。 至此,一个完整的EOS卡牌游戏就制作完成了。 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg","https://cdn.steemitimages.com/DQmfGqPk1Vuomn3qYfPbaLdtKKuXCjHmoDdDhXGWzMNGSYy/eost14-01.png","https://cdn.steemitimages.com/DQmWJVovkJci4CRjXnyPc7pFW9e1ALamf251VLFdA92kcmA/eost14-02.png"],"links":["https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-8/frontend/src/components/Game/components/GameInfo/components","https://battles.eos.io/tutorial/lesson5/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #29301056/Trx 175e9ac68a5cf2a19367e623ecf083dbd2368287
View Raw JSON Data
{
  "trx_id": "175e9ac68a5cf2a19367e623ecf083dbd2368287",
  "block": 29301056,
  "trx_in_block": 4,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T09:46:42",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "651hms-eos",
      "title": "手把手教你玩eos:卡牌游戏第八课——优化细节体验",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg)\n\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十四篇。本篇教程是卡牌游戏的最后一课,讲解怎么进一步优化整个游戏的细节体验。\n\n\n0.2 学习内容\n相关准备\n编写前端代码\n测试代码\n\n0.3 机器环境\ncpu: 1核\n内存: 8G\n操作系统:CentOS 7.4 64位\n服务器所在地:香港\n\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n\n1 相关准备\n1.1 课程目标\n在本课程中,我们将优化游戏细节体验,比如添加游戏帮助对话框,进度提示,优化加载体验等等。\n\n1.2 准备工作\n进入开发环境容器\ndocker exec -it eosdev /bin/bash\n进入前端文件夹\ncd /eos-work/frontend/\n\n2 编写前端代码\n2.1 添加游戏帮助对话框\n在GameInfo中添加RulesModal模态对话框\n\ncd ./src/components/Game/components/GameInfo\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-8/frontend/src/components/Game/components/GameInfo/components\n在GameInfo.jsx中加入RulesModal组件\n\nvi GameInfo.jsx\n更新代码如下:\n\nimport React, { Component } from 'react';\n// Components\nimport { Button } from 'components';\n//在此次添加引用\n// Game subcomponents\nimport { RulesModal } from './components';\nclass Info extends Component {\nrender() {\n// Extract data and event functions from props\nconst { className, deckCardCount, handCardCount, onEndGame } = this.props;\n// Display:\n// Round number: 18 <-- ((max deck = 17) + 1) - Deck Cards - Hand Cards\n// Rules button to trigger a modal\n// Button to end the current game\nreturn (\n<div className={`Info${ className ? ' ' + className : '' }`}>\n{ <p>ROUND  className=\"round-number\">`{ 18 - deckCardCount - handCardCount }/17 </p> }\n//在此处添加组件\n\n<div><Button onClick={ onEndGame } className=\"small red\">QUIT</Button></div>\n</div>\n)\n}\n}\nexport default Info;\n\n\n2.2 添加进度提示\n\ncd /eos-work/frontend/src/components/Button/\n\nvi Button.jsx\n编辑代码如下:\n\nimport React, { Component } from 'react';\nclass Button extends Component {\nconstructor(props) {\n// Inherit constructor\nsuper(props);\n// Component state setup\nthis.state = {\nloading: false,\n};\n// Bind functions\nthis.handleClick = this.handleClick.bind(this);\n}\nhandleClick() {\nconst { onClick } = this.props;\n// Show the loading indicator in case the action to be performed takes too long\nthis.setState({ loading: true });\n// If the prop onClick is a function, invoke it and stores its return value in ``promise``\n// If the prop onClick is NOT a function, the value of ``promise`` will be false\nconst promise = typeof onClick === \"function\" && onClick();\n// If ``promise`` is a function (a Promise), invoke setState after it has been resolved.\nif (promise && typeof promise.then === \"function\") {\nreturn promise.then(() => {\nthis.isComponentMounted && this.setState({ loading: false });\n});\n}\n// Otherwise, just invoke setState directly\nthis.isComponentMounted && this.setState({ loading: false });\n}\ncomponentDidMount() {\nthis.isComponentMounted = true;\n}\ncomponentWillUnmount() {\nthis.isComponentMounted = false;\n}\nrender() {\nconst { className, type, style, children } = this.props;\nlet { loading } = this.state;\n// Enable the loading CSS class if either the private state attribute `loading`\n// or the props `loading` is true\nloading = loading || this.props.loading;\nreturn (\n<button\nclassName={`Button${ className ? ' ' + className : '' }${ loading ? ' loading' : '' }`}\nonClick={ this.handleClick }\n{ ...{ type, style } }\n>{ children }</button>\n);\n}\n}\nexport default Button;\n在Game.jsx中更新引用\n\ncd /eos-work/frontend/src/components/Game/\nvi Game.jsx\n编辑代码如下:\n\n// React core\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Game subcomponents\nimport { GameInfo, GameMat, PlayerProfile, Resolution } from './components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services'; \nclass Game extends Component {\nconstructor(props) {\n// Inherit constructor\nsuper(props);\n// State for showing/hiding components when the API (blockchain) request is loading\nthis.state = {\nloading: true,\n};\n// Bind functions\nthis.loadUser = this.loadUser.bind(this);\nthis.handleStartGame = this.handleStartGame.bind(this);\nthis.handlePlayCard = this.handlePlayCard.bind(this);\nthis.handleNextRound = this.handleNextRound.bind(this);\nthis.handleEndGame = this.handleEndGame.bind(this);\n// Call `loadUser` before mounting the app\nthis.loadUser();\n}\n// Get latest user object from blockchain\nloadUser() {\n// Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux\nconst { setUser, user: { name } } = this.props;\n// Send request the blockchain by calling the ApiService,\n// Get the user object and store the `win_count`, `lost_count` and `game_data` object\nreturn ApiService.getUserByName(name).then(user => {\nsetUser({\nwin_count: user.win_count,\nlost_count: user.lost_count,\ngame: user.game_data,\n});\n// Set the loading state to false for displaying the app\nthis.setState({ loading: false });\n});\n}\nhandleStartGame() {\n// Send a request to API (blockchain) to start game\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.startGame().then(()=>{\nreturn this.loadUser();\n});\n}\nhandlePlayCard(cardIdx) {\n// Extract `user.game` of `UserReducer` from redux\nconst { user: { game } } = this.props;\n// If it is an empty card, not going to do anything\nif (game.hand_player[cardIdx] === 0) {\nreturn;\n}\n// Show the loading indicator if the connection took too long\nthis.setState({ loading: true });\n// Send a request to API (blockchain) to play card with card index\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.playCard(cardIdx).then(()=>{\nreturn this.loadUser();\n});\n}\nhandleNextRound() {\n// Send a request to API (blockchain) to trigger next round\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.nextRound().then(()=>{\nreturn this.loadUser();\n});\n}\nhandleEndGame() {\n// Send a request to API (blockchain) to end the game\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.endGame().then(()=>{\nreturn this.loadUser();\n});\n}\nrender() {\n// Extract data from state and user data of `UserReducer` from redux\nconst { loading } = this.state;\nconst { user: { name, win_count, lost_count, game } } = this.props;\n// Flag to indicate if the game has started or not\n// By checking if the deckCard of AI is still 17 (max card)\nconst isGameStarted = game && game.deck_ai.length !== 17;\n// If game hasn't started, display `PlayerProfile`\n// If game has started, display `GameMat`, `Resolution`, `Info` screen\nreturn (\n<section className={`Game${ (loading ? \" loading\" : \"\") }`}>\n{ !isGameStarted ?\n<PlayerProfile\nname={ name }\nwinCount={ win_count }\nlostCount={ lost_count }\nonLogout={ this.handleLogout }\nonStartGame={ this.handleStartGame }\n/>\n:\n<div className=\"container\">\n<GameMat\ndeckCardCount={ game.deck_ai.length }\naiLife={ game.life_ai }\naiHandCards={ game.hand_ai }\naiName=\"COMPUTER\"\nplayerLife={ game.life_player }\nplayerHandCards={ game.hand_player }\nplayerName={ name }\nonPlayCard={ this.handlePlayCard }\n/>\n<Resolution\nstatus={ game.status }\naiCard={ game.selected_card_ai }\naiName=\"COMPUTER\"\naiLost={ game.life_lost_ai }\nplayerCard={ game.selected_card_player }\nplayerName={ name }\nplayerLost={ game.life_lost_player }\nonNextRound={ this.handleNextRound }\nonEndGame={ this.handleEndGame }\n/>\n<GameInfo\ndeckCardCount={ game.deck_ai.length }\nhandCardCount={ game.hand_ai.filter( x => x > 0 ).length }\nonEndGame={ this.handleEndGame }\n/>\n</div>\n}\n{\nisGameStarted && loading &&\n<div className=\"spinner\">\n<div className=\"image\"></div>\n<div className=\"circles\">\n<div className=\"circle\">\n<div className=\"inner\"></div>\n</div>\n<div className=\"circle\">\n<div className=\"inner\"></div>\n</div>\n<div className=\"circle\">\n<div className=\"inner\"></div>\n</div>\n<div className=\"circle\">\n<div className=\"inner\"></div>\n</div>\n<div className=\"circle\">\n<div className=\"inner\"></div>\n</div>\n</div>\n</div>\n}\n</section>\n)\n}\n}\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n\n// Map the following action to props\nconst mapDispatchToProps = {\nsetUser: UserAction.setUser,\n};\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(Game);\n\n2.3 优化加载体验\n现在每次刷新游戏屏幕时都会短暂显示登录屏幕。\n\n这是由ApiService从区块链获取最新用户数据引起的。\n\n\n在检索用户数据时,dApp认为用户没有登录。\n\n\n为了防止这种情况,我们将向App.jsx添加一个名为loading的组件状态。\n\n\n在检索区块链数据时出现,直到有反馈,确定是应用是在登录页面,游戏结束屏幕还是个人资料屏幕等等。\n\ncd /eos-work/frontend/src/components/Login/\n\nvi Login.jsx\n更新代码如下:\n\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Components\nimport { Button } from 'components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services';\nclass Login extends Component {\nconstructor(props) {\n// Inherit constructor\nsuper(props);\n// State for form data and error message\nthis.state = {\nform: {\nusername: '',\nkey: '',\nerror: '',\n},\nisSigningIn: false,\n}\n// Bind functions\nthis.handleChange = this.handleChange.bind(this);\nthis.handleSubmit = this.handleSubmit.bind(this);\n}\n\n// Runs on every keystroke to update the React state\nhandleChange(event) {\nconst { name, value } = event.target;\nconst { form } = this.state;\n\nthis.setState({\nform: {\n...form,\n[name]: value,\nerror: '',\n},\n});\n}\n\ncomponentDidMount() {\nthis.isComponentMounted = true;\n}\n\ncomponentWillUnmount() {\nthis.isComponentMounted = false;\n}\n\n// Handle form submission to call api\nhandleSubmit(event) {\n// Stop the default form submit browser behaviour\nevent.preventDefault();\n// Extract `form` state\nconst { form } = this.state;\n// Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux\nconst { setUser } = this.props;\n// Set loading spinner to the button\nthis.setState({ isSigningIn: true });\n// Send a login transaction to the blockchain by calling the ApiService,\n// If it successes, save the username to redux store\n// Otherwise, save the error state for displaying the message\nreturn ApiService.login(form)\n.then(() => {\nsetUser({ name: form.username });\n})\n.catch(err => {\nthis.setState({ error: err.toString() });\n})\n.finally(() => {\nif (this.isComponentMounted) {\nthis.setState({ isSigningIn: false });\n}\n});\n}\n\nrender() {\n// Extract data from state\nconst { form, error, isSigningIn } = this.state;\n\nreturn (\n<div className=\"Login\">\n<div className=\"title\">Elemental Battles - powered by EOSIO</div>\n<div className=\"description\">Please use the Account Name and Private Key generated in the previous page to log into the game.</div>\n<form name=\"form\" onSubmit={ this.handleSubmit }>\n<div className=\"field\">\nAccount name\n<input\ntype=\"text\"\nname=\"username\"\nvalue={ form.username }\nplaceholder=\"All small letters, a-z, 1-5 or dot, max 12 characters\"\nonChange={ this.handleChange }\npattern=\"[\\.a-z1-5]{2,12}\"\nrequired\n/>\n</div>\n<div className=\"field\">\nPrivate key\n<input\ntype=\"password\"\nname=\"key\"\nvalue={ form.key }\nonChange={ this.handleChange }\npattern=\"^.{51,}$\"\nrequired\n/>\n</div>\n<div className=\"field form-error\">\n{ error && < className=\"error\"> { error } > }\n</div>\n<div className=\"bottom\">\n<Button type=\"submit\" className=\"green\" loading={ isSigningIn }>\n{ \"CONFIRM\" }\n</Button>\n</div>\n</form>\n</div>\n)\n}\n}\n\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n\n// Map the following action to props\nconst mapDispatchToProps = {\nsetUser: UserAction.setUser,\n};\n\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(Login);\n再在App.jsx中更新引用\n\ncd /eos-work/frontend/src/components/App/\n\nvi App.jsx\n更新代码如下:\n\n// React core\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Components\nimport { Game, Login } from 'components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services';\n\nclass App extends Component {\n\nconstructor(props) {\n// Inherit constructor\nsuper(props);\n\n// 此处添加状态,默认loading为true\n// State for showing/hiding components when the API (blockchain) request is loading\nthis.state = {\nloading: true,\n};\n// Bind functions\nthis.getCurrentUser = this.getCurrentUser.bind(this);\n// Call getCurrentUser before mounting the app\nthis.getCurrentUser();\n}\n\ngetCurrentUser() {\n// Extract setUser of UserAction from redux\nconst { setUser } = this.props;\n// Send a request to API (blockchain) to get the current logged in user\nreturn ApiService.getCurrentUser()\n// If the server return a username\n.then(username => {\n// Save the username to redux store\n// For structure, ref: ./frontend/src/reducers/UserReducer.js\nsetUser({ name: username });\n})\n// To ignore 401 console error\n.catch(() => {})\n//在获取到区块链数据反馈后,设置loading状态为false\n// Run the following function no matter the server return success or error\n.finally(() => {\n// Set the loading state to false for displaying the app\nthis.setState({ loading: false });\n});\n}\n\nrender() {\n// Extract data from state and props (`user` is from redux)\nconst { loading } = this.state;\nconst { user: { name, game } } = this.props;\n\n// 确定游戏处于什么状态\n// Determine the app status for styling\nlet appStatus = \"login\";\nif (game && game.status !== 0) {\nappStatus = \"game-ended\";\n} else if (game && game.selected_card_ai > 0) {\nappStatus = \"card-selected\";\n} else if (game && game.deck_ai.length !== 17) {\nappStatus = \"started\";\n} else if (name) {\nappStatus = \"profile\";\n}\n\n// Set class according to loading state, it will hide the app (ref to css file)\n// If the username is set in redux, display the Game component\n// If the username is NOT set in redux, display the Login component\nreturn (\n<div className={ `App status-${ appStatus }${ loading ? \" loading\" : \"\" }` }>\n{ name &&  }\n{ !name &&   }\n</div>\n);\n}\n\n}\n\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n\n// Map the following action to props\nconst mapDispatchToProps = {\nsetUser: UserAction.setUser,\n};\n\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(App);\n\n3 测试代码\ncd /eos-work/frontend\n\nnpm start\n在浏览器中输入网址测试。\n\n\n点击右边的rules按钮查看游戏规则帮助\n\n![eost14-01.png](https://cdn.steemitimages.com/DQmfGqPk1Vuomn3qYfPbaLdtKKuXCjHmoDdDhXGWzMNGSYy/eost14-01.png)\n\n选择卡牌后,在等待时会出现进度加载提示:\n![eost14-02.png](https://cdn.steemitimages.com/DQmWJVovkJci4CRjXnyPc7pFW9e1ALamf251VLFdA92kcmA/eost14-02.png)\n\n还有刷新后回到主界面等等,就不一一截图了。\n\n\n至此,一个完整的EOS卡牌游戏就制作完成了。\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n\nEOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg\",\"https://cdn.steemitimages.com/DQmfGqPk1Vuomn3qYfPbaLdtKKuXCjHmoDdDhXGWzMNGSYy/eost14-01.png\",\"https://cdn.steemitimages.com/DQmWJVovkJci4CRjXnyPc7pFW9e1ALamf251VLFdA92kcmA/eost14-02.png\"],\"links\":[\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-8/frontend/src/components/Game/components/GameInfo/components\",\"https://battles.eos.io/tutorial/lesson5/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 6t94gc-eos
2019/01/09 09:27:48
votereoswing
authoreoswing
permlink6t94gc-eos
weight10000 (100.00%)
Transaction InfoBlock #29300678/Trx 864a10db2cbedcba1914d7924b940c71c57ee82c
View Raw JSON Data
{
  "trx_id": "864a10db2cbedcba1914d7924b940c71c57ee82c",
  "block": 29300678,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-09T09:27:48",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "6t94gc-eos",
      "weight": 10000
    }
  ]
}
steemdelegated 18.406 SP to @eoswing
2019/01/07 22:35:57
delegatorsteem
delegateeeoswing
vesting shares29936.536048 VESTS
Transaction InfoBlock #29258864/Trx b41d6d4632cea60f8182fed58e9a32f111307f3b
View Raw JSON Data
{
  "trx_id": "b41d6d4632cea60f8182fed58e9a32f111307f3b",
  "block": 29258864,
  "trx_in_block": 11,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-07T22:35:57",
  "op": [
    "delegate_vesting_shares",
    {
      "delegator": "steem",
      "delegatee": "eoswing",
      "vesting_shares": "29936.536048 VESTS"
    }
  ]
}
bukilandupvoted (0.63%) @eoswing / 6t94gc-eos
2019/01/02 09:40:15
voterbukiland
authoreoswing
permlink6t94gc-eos
weight63 (0.63%)
Transaction InfoBlock #29099548/Trx 377c40da9270161e67b7da9f2bd1579e2f955939
View Raw JSON Data
{
  "trx_id": "377c40da9270161e67b7da9f2bd1579e2f955939",
  "block": 29099548,
  "trx_in_block": 39,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-02T09:40:15",
  "op": [
    "vote",
    {
      "voter": "bukiland",
      "author": "eoswing",
      "permlink": "6t94gc-eos",
      "weight": 63
    }
  ]
}
devsupupvoted (0.69%) @eoswing / 6t94gc-eos
2019/01/02 09:39:39
voterdevsup
authoreoswing
permlink6t94gc-eos
weight69 (0.69%)
Transaction InfoBlock #29099536/Trx fc548111d7407c2700ba10f088c5ac0809705cff
View Raw JSON Data
{
  "trx_id": "fc548111d7407c2700ba10f088c5ac0809705cff",
  "block": 29099536,
  "trx_in_block": 10,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-02T09:39:39",
  "op": [
    "vote",
    {
      "voter": "devsup",
      "author": "eoswing",
      "permlink": "6t94gc-eos",
      "weight": 69
    }
  ]
}
eoswingpublished a new post: 6t94gc-eos
2019/01/02 09:24:42
parent author
parent permlinkeos
authoreoswing
permlink6t94gc-eos
title手把手教你玩eos:卡牌游戏第七课——完善游戏流程
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十三篇。本篇教程主要学习卡牌游戏的整个游戏流程代码编写。 0.2 学习内容 相关准备 智能合约代码编写和部署 编写前端代码 测试代码 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 在本课程中,我们将完善整个游戏流程,确保体验一个完整的游戏。同时,根据比赛结果,提示结束游戏并开始下一轮。 1.2 规则讲解 在每个回合结束时我们继续前进到下一轮,但在此之前,检查游戏状态以确定游戏是否已经完成是很重要的。 在以下情况,结束游戏: AI HP达到零,则玩家赢得游戏; 玩家HP达到零,则玩家输掉游戏; 如果玩家和AI都用完卡片,那么: 玩家HP高于AI HP,则玩家赢得游戏; AI HP比玩家HP更高,则AI赢得了比赛。 如果游戏尚未结束,则玩家可以选择前进到下一轮并玩另一张牌,或者认输并结束游戏。 1.3 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入后端智能合约文件夹 cd /eos-work/contracts/cardgame 2 智能合约代码编写和部署 2.1 编写合约代码 打开cardgame.hpp文件: vi cardgame.hpp 编辑代码,添加代码如下: void resolve_selected_cards(game& game_data); //在上面代码行后添加如下代码 //===下面为添加代码=== void update_game_status(user_info& user); //====== //...... void startgame(account_name username); //在上面代码行后添加如下代码 //===下面为添加代码=== void endgame(account_name username); void nextround(account_name username); 打开gameplay.cpp文件: vi gameplay.cpp 在所有代码行的最后面添加代码如下: //在代码行的最后添加如下代码 // Check the current game board and update the game status accordingly void cardgame::update_game_status(user_info& user) { game& game_data = user.game_data; if (game_data.life_ai <= 0) { // Check the AI's HP game_data.status = PLAYER_WON; } else if (game_data.life_player <= 0) { // Check the player's HP game_data.status = PLAYER_LOST; } else { // Neither player has their HP reduced to 0 // Check whether the game has finished (i.e., no more cards in both hands) const auto is_empty_slot = [&](const auto& id) { return card_dict.at(id).type == EMPTY; }; bool player_finished = std::all_of(game_data.hand_player.begin(), game_data.hand_player.end(), is_empty_slot); bool ai_finished = std::all_of(game_data.hand_ai.begin(), game_data.hand_ai.end(), is_empty_slot); // If one of them has run out of card, the other must have run out of card too if (player_finished || ai_finished) { if (game_data.life_player > game_data.life_ai) { game_data.status = PLAYER_WON; } else { game_data.status = PLAYER_LOST; } } } // Update the lost/ win count accordingly if (game_data.status == PLAYER_WON) { user.win_count++; } else if (game_data.status == PLAYER_LOST) { user.lost_count++; } } 打开cardgame.cpp文件: vi cardgame.cpp 编辑代码,在startgame函数后添加代码如下: void cardgame::startgame(account_name username) { // Ensure this action is authorized by the player require_auth(username); auto& user = _users.get(username, "User doesn't exist"); _users.modify(user, username, [&](auto& modified_user) { // Create a new game game game_data; // Draw 4 cards each for the player and the AI for (uint8_t i = 0; i < 4; i++) { draw_one_card(game_data.deck_player, game_data.hand_player); draw_one_card(game_data.deck_ai, game_data.hand_ai); } // Assign the newly created game to the player modified_user.game_data = game_data; }); } //在上面代码行后添加如下代码 //===下面为添加代码=== void cardgame::endgame(account_name username) { // Ensure this action is authorized by the player require_auth(username); // Get the user and reset the game auto& user = _users.get(username, "User doesn't exist"); _users.modify(user, username, [&](auto& modified_user) { modified_user.game_data = game(); }); } void cardgame::nextround(account_name username) { // Ensure this action is authorized by the player require_auth(username); auto& user = _users.get(username, "User doesn't exist"); // Verify game status eosio_assert(user.game_data.status == ONGOING, "nextround: This game has ended. Please start a new one."); eosio_assert(user.game_data.selected_card_player != 0 && user.game_data.selected_card_ai != 0, "nextround: Please play a card first."); _users.modify(user, username, [&](auto& modified_user) { game& game_data = modified_user.game_data; // Reset selected card and damage dealt game_data.selected_card_player = 0; game_data.selected_card_ai = 0; game_data.life_lost_player = 0; game_data.life_lost_ai = 0; // Draw card for the player and the AI if (game_data.deck_player.size() > 0) draw_one_card(game_data.deck_player, game_data.hand_player); if (game_data.deck_ai.size() > 0) draw_one_card(game_data.deck_ai, game_data.hand_ai); }); } //====== 再在startgame函数体中添加一行代码: resolve_selected_cards(game_data); //在上面代码行后添加如下代码 //===下面为添加代码=== update_game_status(modified_user); //====== 最后,在末尾定义abi时,添加函数体: //在最后一行添加nexttround 和 endgame 两个函数 EOSIO_ABI(cardgame, (login)(startgame)(playcard)(nextround)(endgame)) 2.2 部署智能合约覆盖原合约 编译智能合约 编译wast文件 eosiocpp -o cardgame.wast cardgame.cpp 编译abi文件 eosiocpp -g cardgame.abi cardgame.cpp 解锁钱包 cleos wallet unlock -n gamewallet 部署智能合约 cleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active 至此,后端的合约重新部署完成。 3 编写前端代码 3.1 编辑Game.jsx cd /eos-work/frontend/src/components/Game/ vi Game.jsx 更新代码如下: //在rander()前添加handleNextRound和handleEndGame两个函数 handleNextRound() { // Send a request to API (blockchain) to trigger next round // And call `loadUser` again for react to render latest game status to UI return ApiService.nextRound().then(()=>{ return this.loadUser(); }); } handleEndGame() { // Send a request to API (blockchain) to end the game // And call `loadUser` again for react to render latest game status to UI return ApiService.endGame().then(()=>{ return this.loadUser(); }); } //在render()函数中添加两个函数体, render() { // Extract data from user data of `UserReducer` from redux const { user: { name, win_count, lost_count, game } } = this.props; // Flag to indicate if the game has started or not // By checking if the deckCard of AI is still 17 (max card) const isGameStarted = game && game.deck_ai.length !== 17; // If game hasn't started, display `PlayerProfile` // If game has started, display `GameMat`, `Resolution`, `Info` screen return ( `<section className="Game">` { !isGameStarted ? <PlayerProfile name={ name } winCount={ win_count } lostCount={ lost_count } onStartGame={ this.handleStartGame } /> : <div className="container"> <GameMat deckCardCount={ game.deck_ai.length } aiLife={ game.life_ai } aiHandCards={ game.hand_ai } aiName="COMPUTER" playerLife={ game.life_player } playerHandCards={ game.hand_player } playerName={ name } onPlayCard={ this.handlePlayCard } /> <Resolution status={ game.status } aiCard={ game.selected_card_ai } aiName="COMPUTER" aiLost={ game.life_lost_ai } playerCard={ game.selected_card_player } playerName={ name } playerLost={ game.life_lost_player } //此处为添加内容 onNextRound={ this.handleNextRound } onEndGame={ this.handleEndGame } //=== /> <GameInfo deckCardCount={ game.deck_ai.length } handCardCount={ game.hand_ai.filter( x => x > 0 ).length } //此处为添加内容 onEndGame={ this.handleEndGame } //=== /> </div> } `</section>` ) } 3.2 编辑ApiService.js cd /eos-work/frontend/src/services/ vi ApiService.js 添加代码如下: static playCard(cardIdx) { return takeAction("playcard", { username: localStorage.getItem("cardgame_account"), player_card_idx: cardIdx }); } //在上面代码行后添加如下代码 //===下面为添加代码=== static nextRound() { return takeAction("nextround", { username: localStorage.getItem("cardgame_account") }); } static endGame() { return takeAction("endgame", { username: localStorage.getItem("cardgame_account") }); } //=== 4 测试代码 cd /eos-work/frontend npm start 在浏览器中输入网址测试。 这次,还是保留了上节课程的账号缓存,所以输入网址后直接跳转到对战界面。 ![eost13-01.png](https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost13-01.png) 点击按钮进入游戏主界面: ![eost13-02.png](https://cdn.steemitimages.com/DQmdjLAgwhvQuZ5oZUc1BvZokbfJzbk19V5kAHF4jexFHCV/eost13-02.png) 再次选择卡牌,进行对战: ![eost13-03.png](https://cdn.steemitimages.com/DQmUSeQTcicBKiYfP8bz6G4bP5kqUQbEDYGLdLudEL8MriB/eost13-03.png) 5 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost13-01.png","https://cdn.steemitimages.com/DQmdjLAgwhvQuZ5oZUc1BvZokbfJzbk19V5kAHF4jexFHCV/eost13-02.png","https://cdn.steemitimages.com/DQmUSeQTcicBKiYfP8bz6G4bP5kqUQbEDYGLdLudEL8MriB/eost13-03.png"],"links":["https://api-kylin.eosasia.one","https://battles.eos.io/tutorial/lesson5/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #29099237/Trx f651126bcb07abcc5fcc40a2b69d7099473a8c68
View Raw JSON Data
{
  "trx_id": "f651126bcb07abcc5fcc40a2b69d7099473a8c68",
  "block": 29099237,
  "trx_in_block": 30,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2019-01-02T09:24:42",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "6t94gc-eos",
      "title": "手把手教你玩eos:卡牌游戏第七课——完善游戏流程",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n\n\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十三篇。本篇教程主要学习卡牌游戏的整个游戏流程代码编写。\n\n\n0.2 学习内容\n相关准备\n智能合约代码编写和部署\n编写前端代码\n测试代码\n\n0.3 机器环境\ncpu: 1核\n内存: 8G\n操作系统:CentOS 7.4 64位\n服务器所在地:香港\n\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n\n1 相关准备\n1.1 课程目标\n在本课程中,我们将完善整个游戏流程,确保体验一个完整的游戏。同时,根据比赛结果,提示结束游戏并开始下一轮。\n\n\n1.2 规则讲解\n在每个回合结束时我们继续前进到下一轮,但在此之前,检查游戏状态以确定游戏是否已经完成是很重要的。\n\n\n在以下情况,结束游戏:\n\n\nAI HP达到零,则玩家赢得游戏;\n玩家HP达到零,则玩家输掉游戏;\n\n如果玩家和AI都用完卡片,那么:\n\n\n玩家HP高于AI HP,则玩家赢得游戏;\nAI HP比玩家HP更高,则AI赢得了比赛。\n\n如果游戏尚未结束,则玩家可以选择前进到下一轮并玩另一张牌,或者认输并结束游戏。\n\n\n1.3 准备工作\n进入开发环境容器\ndocker exec -it eosdev /bin/bash\n进入后端智能合约文件夹\n\ncd /eos-work/contracts/cardgame\n2 智能合约代码编写和部署\n2.1 编写合约代码\n打开cardgame.hpp文件:\n\nvi cardgame.hpp\n编辑代码,添加代码如下:\n\nvoid resolve_selected_cards(game& game_data);\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nvoid update_game_status(user_info& user);\n//======\n//......\nvoid startgame(account_name username);\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nvoid endgame(account_name username);\nvoid nextround(account_name username);\n打开gameplay.cpp文件:\n\nvi gameplay.cpp\n在所有代码行的最后面添加代码如下:\n\n//在代码行的最后添加如下代码\n// Check the current game board and update the game status accordingly\nvoid cardgame::update_game_status(user_info& user) {\ngame& game_data = user.game_data;\nif (game_data.life_ai <= 0) {\n// Check the AI's HP\ngame_data.status = PLAYER_WON;\n} else if (game_data.life_player <= 0) {\n// Check the player's HP\ngame_data.status = PLAYER_LOST;\n} else {\n// Neither player has their HP reduced to 0\n// Check whether the game has finished (i.e., no more cards in both hands)\nconst auto is_empty_slot = [&](const auto& id) { return card_dict.at(id).type == EMPTY; };\nbool player_finished = std::all_of(game_data.hand_player.begin(), game_data.hand_player.end(), is_empty_slot);\nbool ai_finished = std::all_of(game_data.hand_ai.begin(), game_data.hand_ai.end(), is_empty_slot);\n\n// If one of them has run out of card, the other must have run out of card too\nif (player_finished || ai_finished) {\nif (game_data.life_player > game_data.life_ai) {\ngame_data.status = PLAYER_WON;\n} else {\ngame_data.status = PLAYER_LOST;\n}\n}\n}\n// Update the lost/ win count accordingly\nif (game_data.status == PLAYER_WON) {\nuser.win_count++;\n} else if (game_data.status == PLAYER_LOST) {\nuser.lost_count++;\n}\n}\n打开cardgame.cpp文件:\n\nvi cardgame.cpp\n编辑代码,在startgame函数后添加代码如下:\n\nvoid cardgame::startgame(account_name username) {\n// Ensure this action is authorized by the player\nrequire_auth(username);\nauto& user = _users.get(username, \"User doesn't exist\");\n_users.modify(user, username, [&](auto& modified_user) {\n// Create a new game\ngame game_data;\n// Draw 4 cards each for the player and the AI\nfor (uint8_t i = 0; i < 4; i++) {\ndraw_one_card(game_data.deck_player, game_data.hand_player);\ndraw_one_card(game_data.deck_ai, game_data.hand_ai);\n}\n// Assign the newly created game to the player\nmodified_user.game_data = game_data;\n});\n}\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nvoid cardgame::endgame(account_name username) {\n// Ensure this action is authorized by the player\nrequire_auth(username);\n// Get the user and reset the game\nauto& user = _users.get(username, \"User doesn't exist\");\n_users.modify(user, username, [&](auto& modified_user) {\nmodified_user.game_data = game();\n});\n}\nvoid cardgame::nextround(account_name username) {\n// Ensure this action is authorized by the player\nrequire_auth(username);\nauto& user = _users.get(username, \"User doesn't exist\");\n// Verify game status\neosio_assert(user.game_data.status == ONGOING,\n\"nextround: This game has ended. Please start a new one.\");\neosio_assert(user.game_data.selected_card_player != 0 && user.game_data.selected_card_ai != 0,\n\"nextround: Please play a card first.\");\n_users.modify(user, username, [&](auto& modified_user) {\ngame& game_data = modified_user.game_data;\n// Reset selected card and damage dealt\ngame_data.selected_card_player = 0;\ngame_data.selected_card_ai = 0;\ngame_data.life_lost_player = 0;\ngame_data.life_lost_ai = 0;\n// Draw card for the player and the AI\nif (game_data.deck_player.size() > 0) draw_one_card(game_data.deck_player, game_data.hand_player);\nif (game_data.deck_ai.size() > 0) draw_one_card(game_data.deck_ai, game_data.hand_ai);\n});\n}\n//======\n再在startgame函数体中添加一行代码:\n\nresolve_selected_cards(game_data);\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nupdate_game_status(modified_user);\n//======\n最后,在末尾定义abi时,添加函数体:\n\n//在最后一行添加nexttround 和 endgame 两个函数\nEOSIO_ABI(cardgame, (login)(startgame)(playcard)(nextround)(endgame))\n2.2 部署智能合约覆盖原合约\n编译智能合约\n编译wast文件\neosiocpp -o cardgame.wast cardgame.cpp\n编译abi文件\n\neosiocpp -g cardgame.abi cardgame.cpp\n解锁钱包\n\ncleos wallet unlock -n gamewallet\n部署智能合约\n\ncleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active\n至此,后端的合约重新部署完成。\n\n3 编写前端代码\n3.1 编辑Game.jsx\ncd /eos-work/frontend/src/components/Game/\nvi Game.jsx\n更新代码如下:\n\n//在rander()前添加handleNextRound和handleEndGame两个函数\nhandleNextRound() {\n// Send a request to API (blockchain) to trigger next round\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.nextRound().then(()=>{\nreturn this.loadUser();\n});\n}\nhandleEndGame() {\n// Send a request to API (blockchain) to end the game\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.endGame().then(()=>{\nreturn this.loadUser();\n});\n}\n//在render()函数中添加两个函数体,\nrender() {\n// Extract data from user data of `UserReducer` from redux\nconst { user: { name, win_count, lost_count, game } } = this.props;\n// Flag to indicate if the game has started or not\n// By checking if the deckCard of AI is still 17 (max card)\nconst isGameStarted = game && game.deck_ai.length !== 17;\n// If game hasn't started, display `PlayerProfile`\n// If game has started, display `GameMat`, `Resolution`, `Info` screen\nreturn (\n`<section className=\"Game\">`\n{ !isGameStarted ?\n<PlayerProfile\nname={ name }\nwinCount={ win_count }\nlostCount={ lost_count }\nonStartGame={ this.handleStartGame }\n/>\n:\n<div className=\"container\">\n<GameMat\ndeckCardCount={ game.deck_ai.length }\naiLife={ game.life_ai }\naiHandCards={ game.hand_ai }\naiName=\"COMPUTER\"\nplayerLife={ game.life_player }\nplayerHandCards={ game.hand_player }\nplayerName={ name }\nonPlayCard={ this.handlePlayCard }\n/>\n<Resolution\nstatus={ game.status }\naiCard={ game.selected_card_ai }\naiName=\"COMPUTER\"\naiLost={ game.life_lost_ai }\nplayerCard={ game.selected_card_player }\nplayerName={ name }\nplayerLost={ game.life_lost_player }\n//此处为添加内容\nonNextRound={ this.handleNextRound }\nonEndGame={ this.handleEndGame }\n//===\n/>\n<GameInfo\ndeckCardCount={ game.deck_ai.length }\nhandCardCount={ game.hand_ai.filter( x => x > 0 ).length }\n//此处为添加内容\nonEndGame={ this.handleEndGame }\n//===\n/>\n</div>\n}\n`</section>`\n)\n}\n\n3.2 编辑ApiService.js\ncd /eos-work/frontend/src/services/\nvi ApiService.js\n添加代码如下:\n\nstatic playCard(cardIdx) {\nreturn takeAction(\"playcard\", { username: localStorage.getItem(\"cardgame_account\"), player_card_idx: cardIdx });\n}\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nstatic nextRound() {\nreturn takeAction(\"nextround\", { username: localStorage.getItem(\"cardgame_account\") });\n}\nstatic endGame() {\nreturn takeAction(\"endgame\", { username: localStorage.getItem(\"cardgame_account\") });\n}\n//===\n4 测试代码\ncd /eos-work/frontend\nnpm start\n在浏览器中输入网址测试。\n\n\n这次,还是保留了上节课程的账号缓存,所以输入网址后直接跳转到对战界面。\n\n![eost13-01.png](https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost13-01.png)\n\n点击按钮进入游戏主界面:\n\n![eost13-02.png](https://cdn.steemitimages.com/DQmdjLAgwhvQuZ5oZUc1BvZokbfJzbk19V5kAHF4jexFHCV/eost13-02.png)\n\n再次选择卡牌,进行对战:\n\n![eost13-03.png](https://cdn.steemitimages.com/DQmUSeQTcicBKiYfP8bz6G4bP5kqUQbEDYGLdLudEL8MriB/eost13-03.png)\n\n5 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n\nEOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost13-01.png\",\"https://cdn.steemitimages.com/DQmdjLAgwhvQuZ5oZUc1BvZokbfJzbk19V5kAHF4jexFHCV/eost13-02.png\",\"https://cdn.steemitimages.com/DQmUSeQTcicBKiYfP8bz6G4bP5kqUQbEDYGLdLudEL8MriB/eost13-03.png\"],\"links\":[\"https://api-kylin.eosasia.one\",\"https://battles.eos.io/tutorial/lesson5/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2018/12/26 10:29:54
voterthetroublenotes
authoreoswing
permlink5safd2-eos
weight200 (2.00%)
Transaction InfoBlock #28899070/Trx 5c23aff6ed198511fc4141ee9e0d52729ef1e608
View Raw JSON Data
{
  "trx_id": "5c23aff6ed198511fc4141ee9e0d52729ef1e608",
  "block": 28899070,
  "trx_in_block": 9,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-26T10:29:54",
  "op": [
    "vote",
    {
      "voter": "thetroublenotes",
      "author": "eoswing",
      "permlink": "5safd2-eos",
      "weight": 200
    }
  ]
}
eoswingpublished a new post: 5safd2-eos
2018/12/26 10:09:54
parent author
parent permlinkeos
authoreoswing
permlink5safd2-eos
title手把手教你玩eos:卡牌游戏第六课——战斗部分
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十二篇。本篇教程主要学习卡牌游戏的战斗场景部分代码编写。 0.2 学习内容 相关准备 智能合约代码编写和部署 编写前端代码 测试代码 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 现在,我们需要计算战斗结果并扣除玩家或AI的HP。 在本课中,我们将实现解决玩家和AI之间战斗所需的智能合约功能。 战斗将由每轮打出的牌决定,使用这些功能根据牌攻击点和类型计算伤害。 最后,我们将添加UI组件以在屏幕上显示每轮的结果。 1.2 规则讲解 元素战斗中的每张牌都由其攻击力和元素类型定义。 有5种不同的类型,包括火,木,水,中性和虚空。 火(Fire),木(wood)和水(water)是形成元素相互克制的牌。 其中,火克制木,木克制水,水克制火。当一个元素克制另一个元素时,它的攻击力增加1。 ![eost12-01.png](https://cdn.steemitimages.com/DQmZy6MnaHV9LAQsE4Mw4PyxbHFvD4vdFBK8AyAymRZsAsU/eost12-01.png) 中性(Neutral)和虚空(Void)是特殊牌。 中立没有元素兼容性,所以有中立牌的一轮中没有攻击力调整。 而一张虚空牌导致这一轮没有造成伤害。 举个栗子: 玩家1出木(Wood) 攻击力2 玩家2出火(Fire) 攻击力2 因为火克制木,玩家2就获得+1攻击 这导致: 玩家1攻击力为2 玩家2攻击力为3 所以玩家2获得胜利,玩家1则输了1HP。 ![eost12-02.jpg](https://cdn.steemitimages.com/DQmVEXNYPbGCBpK9G6qTdZ1KX9xobFbKQWneE6RQPjFmFSN/eost12-02.jpg) 1.3 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入后端智能合约文件夹 cd /eos-work/contracts/cardgame 2 智能合约代码编写和部署 2.1 编写合约代码 打开cardgame.hpp文件: vi cardgame.hpp 编辑代码,添加代码如下: int ai_choose_card(const game& game_data); //在上面代码行后添加如下代码 //===下面为添加代码=== void resolve_selected_cards(game& game_data); //====== 打开gameplay.cpp文件: vi gameplay.cpp 编辑代码,在cardgame::calculate_attack_point函数体中添加代码如下: int cardgame::calculate_attack_point(const card& card1, const card& card2) { int result = card1.attack_point; //在上面代码行后添加如下代码 //===下面为添加代码=== //Add elemental compatibility bonus of 1 if ((card1.type == FIRE && card2.type == WOOD) || (card1.type == WOOD && card2.type == WATER) || (card1.type == WATER && card2.type == FIRE)) { result++; } //====== 同时,在所有代码行的最后面添加代码如下: //在代码行的最后添加如下代码 // Resolve selected cards and update the damage dealt void cardgame::resolve_selected_cards(game& game_data) { const auto player_card = card_dict.at(game_data.selected_card_player); const auto ai_card = card_dict.at(game_data.selected_card_ai); // For type VOID, we will skip any damage calculation if (player_card.type == VOID || ai_card.type == VOID) return; int player_attack_point = calculate_attack_point(player_card, ai_card); int ai_attack_point = calculate_attack_point(ai_card, player_card); // Damage calculation if (player_attack_point > ai_attack_point) { // Deal damage to the AI if the AI card's attack point is higher int diff = player_attack_point - ai_attack_point; game_data.life_lost_ai = diff; game_data.life_ai -= diff; } else if (ai_attack_point > player_attack_point) { // Deal damage to the player if the player card's attack point is higher int diff = ai_attack_point - player_attack_point; game_data.life_lost_player = diff; game_data.life_player -= diff; } } 打开cardgame.cpp文件: vi cardgame.cpp 编辑代码,添加代码如下: game_data.hand_ai[ai_card_idx] = 0; //在上面代码行后添加如下代码 //===下面为添加代码=== resolve_selected_cards(game_data); //====== 2.2 部署智能合约覆盖原合约 编译智能合约 编译wast文件 eosiocpp -o cardgame.wast cardgame.cpp 编译abi文件 eosiocpp -g cardgame.abi cardgame.cpp 解锁钱包 cleos wallet unlock -n gamewallet 部署智能合约 cleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active 至此,后端的合约重新部署完成。 3 编写前端代码 3.1 下载Resolution组件 cd /eos-work/frontend/src/components/Game/components/ svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-6/frontend/src/components/Game/components/Resolution 3.2 整合组件 vi index.js 更新代码如下: import Card from './Card'; import GameInfo from './GameInfo'; import GameMat from './GameMat'; import HandCards from './HandCards'; import PlayerInfo from './PlayerInfo'; import PlayerProfile from './PlayerProfile'; import Resolution from './Resolution'; export { Card, GameInfo, GameMat, HandCards, PlayerInfo, PlayerProfile, Resolution, } 返回上一级,编辑Game.jsx cd .. vi Game.jsx 更新代码如下: // React core import React, { Component } from 'react'; import { connect } from 'react-redux'; // Game subcomponents //此次引用Resolution组件 import { GameInfo, GameMat, PlayerProfile, Resolution } from './components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class Game extends Component { constructor(props) { // Inherit constructor super(props); // Bind functions this.loadUser = this.loadUser.bind(this); this.handleStartGame = this.handleStartGame.bind(this); this.handlePlayCard = this.handlePlayCard.bind(this); // Call `loadUser` before mounting the app this.loadUser(); } // Get latest user object from blockchain loadUser() { // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux const { setUser, user: { name } } = this.props; // Send request the blockchain by calling the ApiService, // Get the user object and store the `win_count`, `lost_count` and `game_data` object return ApiService.getUserByName(name).then(user => { setUser({ win_count: user.win_count, lost_count: user.lost_count, game: user.game_data, }); }); } handleStartGame() { // Send a request to API (blockchain) to start game // And call `loadUser` again for react to render latest game status to UI return ApiService.startGame().then(()=>{ return this.loadUser(); }); } handlePlayCard(cardIdx) { // Extract `user.game` of `UserReducer` from redux const { user: { game } } = this.props; // If it is an empty card, not going to do anything if (game.hand_player[cardIdx] === 0) { return; } // Send a request to API (blockchain) to play card with card index // And call `loadUser` again for react to render latest game status to UI return ApiService.playCard(cardIdx).then(()=>{ return this.loadUser(); }); } render() { // Extract data from user data of `UserReducer` from redux const { user: { name, win_count, lost_count, game } } = this.props; // Flag to indicate if the game has started or not // By checking if the deckCard of AI is still 17 (max card) const isGameStarted = game && game.deck_ai.length !== 17; // If game hasn't started, display `PlayerProfile` // If game has started, display `GameMat`, `Resolution`, `Info` screen //此次添加调用Resolution组件 return ( `<section className="Game">` { !isGameStarted ? <PlayerProfile name={ name } winCount={ win_count } lostCount={ lost_count } onStartGame={ this.handleStartGame } /> : <div className="container"> <GameMat deckCardCount={ game.deck_ai.length } aiLife={ game.life_ai } aiHandCards={ game.hand_ai } aiName="COMPUTER" playerLife={ game.life_player } playerHandCards={ game.hand_player } playerName={ name } onPlayCard={ this.handlePlayCard } /> <Resolution status={ game.status } aiCard={ game.selected_card_ai } aiName="COMPUTER" aiLost={ game.life_lost_ai } playerCard={ game.selected_card_player } playerName={ name } playerLost={ game.life_lost_player } /> <GameInfo deckCardCount={ game.deck_ai.length } handCardCount={ game.hand_ai.filter( x => x > 0 ).length } /> </div> } `</section>` ) } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(Game); 4 测试代码 cd /eos-work/frontend npm start 在浏览器中输入网址测试。 此次,我没有清空上节课程的账号缓存,所以输入网址后直接跳转到对战界面。 ![eost12-03.png](https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost12-03.png) 5 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg","https://cdn.steemitimages.com/DQmZy6MnaHV9LAQsE4Mw4PyxbHFvD4vdFBK8AyAymRZsAsU/eost12-01.png","https://cdn.steemitimages.com/DQmVEXNYPbGCBpK9G6qTdZ1KX9xobFbKQWneE6RQPjFmFSN/eost12-02.jpg","https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost12-03.png"],"links":["https://api-kylin.eosasia.one","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-6/frontend/src/components/Game/components/Resolution","https://battles.eos.io/tutorial/lesson5/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #28898670/Trx a4f6dfbe085087ac1b772893c86c0bcad0f58b85
View Raw JSON Data
{
  "trx_id": "a4f6dfbe085087ac1b772893c86c0bcad0f58b85",
  "block": 28898670,
  "trx_in_block": 20,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-26T10:09:54",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "5safd2-eos",
      "title": "手把手教你玩eos:卡牌游戏第六课——战斗部分",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg)\n\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十二篇。本篇教程主要学习卡牌游戏的战斗场景部分代码编写。\n\n\n0.2 学习内容\n相关准备\n智能合约代码编写和部署\n编写前端代码\n测试代码\n\n0.3 机器环境\ncpu: 1核\n内存: 8G\n操作系统:CentOS 7.4 64位\n服务器所在地:香港\n\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n\n1 相关准备\n1.1 课程目标\n现在,我们需要计算战斗结果并扣除玩家或AI的HP。\n在本课中,我们将实现解决玩家和AI之间战斗所需的智能合约功能。\n战斗将由每轮打出的牌决定,使用这些功能根据牌攻击点和类型计算伤害。\n\n最后,我们将添加UI组件以在屏幕上显示每轮的结果。\n\n\n1.2 规则讲解\n元素战斗中的每张牌都由其攻击力和元素类型定义。\n\n有5种不同的类型,包括火,木,水,中性和虚空。\n\n火(Fire),木(wood)和水(water)是形成元素相互克制的牌。\n\n其中,火克制木,木克制水,水克制火。当一个元素克制另一个元素时,它的攻击力增加1。\n![eost12-01.png](https://cdn.steemitimages.com/DQmZy6MnaHV9LAQsE4Mw4PyxbHFvD4vdFBK8AyAymRZsAsU/eost12-01.png)\n\n中性(Neutral)和虚空(Void)是特殊牌。\n中立没有元素兼容性,所以有中立牌的一轮中没有攻击力调整。\n而一张虚空牌导致这一轮没有造成伤害。\n举个栗子:\n玩家1出木(Wood) 攻击力2\n玩家2出火(Fire) 攻击力2\n因为火克制木,玩家2就获得+1攻击\n这导致:\n玩家1攻击力为2\n玩家2攻击力为3\n所以玩家2获得胜利,玩家1则输了1HP。\n![eost12-02.jpg](https://cdn.steemitimages.com/DQmVEXNYPbGCBpK9G6qTdZ1KX9xobFbKQWneE6RQPjFmFSN/eost12-02.jpg)\n\n1.3 准备工作\n进入开发环境容器\ndocker exec -it eosdev /bin/bash\n\n进入后端智能合约文件夹\ncd /eos-work/contracts/cardgame\n\n\n2 智能合约代码编写和部署\n2.1 编写合约代码\n打开cardgame.hpp文件:\nvi cardgame.hpp\n\n编辑代码,添加代码如下:\nint ai_choose_card(const game& game_data);\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nvoid resolve_selected_cards(game& game_data);\n//======\n\n打开gameplay.cpp文件:\nvi gameplay.cpp\n\n编辑代码,在cardgame::calculate_attack_point函数体中添加代码如下:\nint cardgame::calculate_attack_point(const card& card1, const card& card2) {\nint result = card1.attack_point;\n//在上面代码行后添加如下代码\n//===下面为添加代码===\n//Add elemental compatibility bonus of 1\nif ((card1.type == FIRE && card2.type == WOOD) ||\n(card1.type == WOOD && card2.type == WATER) ||\n(card1.type == WATER && card2.type == FIRE)) {\nresult++;\n}\n//======\n\n同时,在所有代码行的最后面添加代码如下:\n//在代码行的最后添加如下代码\n// Resolve selected cards and update the damage dealt\nvoid cardgame::resolve_selected_cards(game& game_data) {\nconst auto player_card = card_dict.at(game_data.selected_card_player);\nconst auto ai_card = card_dict.at(game_data.selected_card_ai);\n// For type VOID, we will skip any damage calculation\nif (player_card.type == VOID || ai_card.type == VOID) return;\nint player_attack_point = calculate_attack_point(player_card, ai_card);\nint ai_attack_point = calculate_attack_point(ai_card, player_card);\n// Damage calculation\nif (player_attack_point > ai_attack_point) {\n// Deal damage to the AI if the AI card's attack point is higher\nint diff = player_attack_point - ai_attack_point;\ngame_data.life_lost_ai = diff;\ngame_data.life_ai -= diff;\n} else if (ai_attack_point > player_attack_point) {\n// Deal damage to the player if the player card's attack point is higher\nint diff = ai_attack_point - player_attack_point;\ngame_data.life_lost_player = diff;\ngame_data.life_player -= diff;\n}\n}\n\n打开cardgame.cpp文件:\nvi cardgame.cpp\n\n编辑代码,添加代码如下:\ngame_data.hand_ai[ai_card_idx] = 0;\n//在上面代码行后添加如下代码\n//===下面为添加代码===\nresolve_selected_cards(game_data);\n//======\n\n\n2.2 部署智能合约覆盖原合约\n编译智能合约\n编译wast文件\neosiocpp -o cardgame.wast cardgame.cpp\n\n编译abi文件\neosiocpp -g cardgame.abi cardgame.cpp\n\n解锁钱包\ncleos wallet unlock -n gamewallet\n\n部署智能合约\ncleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active\n至此,后端的合约重新部署完成。\n\n\n\n3 编写前端代码\n3.1 下载Resolution组件\ncd /eos-work/frontend/src/components/Game/components/\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-6/frontend/src/components/Game/components/Resolution\n\n\n3.2 整合组件\nvi index.js\n更新代码如下:\nimport Card from './Card';\nimport GameInfo from './GameInfo';\nimport GameMat from './GameMat';\nimport HandCards from './HandCards';\nimport PlayerInfo from './PlayerInfo';\nimport PlayerProfile from './PlayerProfile';\nimport Resolution from './Resolution';\nexport {\nCard,\nGameInfo,\nGameMat,\nHandCards,\nPlayerInfo,\nPlayerProfile,\nResolution,\n}\n\n返回上一级,编辑Game.jsx\ncd ..\nvi Game.jsx\n\n更新代码如下:\n// React core\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Game subcomponents\n//此次引用Resolution组件\nimport { GameInfo, GameMat, PlayerProfile, Resolution } from './components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services';\nclass Game extends Component {\nconstructor(props) {\n// Inherit constructor\nsuper(props);\n// Bind functions\nthis.loadUser = this.loadUser.bind(this);\nthis.handleStartGame = this.handleStartGame.bind(this);\nthis.handlePlayCard = this.handlePlayCard.bind(this);\n// Call `loadUser` before mounting the app\nthis.loadUser();\n}\n// Get latest user object from blockchain\nloadUser() {\n// Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux\nconst { setUser, user: { name } } = this.props;\n// Send request the blockchain by calling the ApiService,\n// Get the user object and store the `win_count`, `lost_count` and `game_data` object\nreturn ApiService.getUserByName(name).then(user => {\nsetUser({\nwin_count: user.win_count,\nlost_count: user.lost_count,\ngame: user.game_data,\n});\n});\n}\nhandleStartGame() {\n// Send a request to API (blockchain) to start game\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.startGame().then(()=>{\nreturn this.loadUser();\n});\n}\nhandlePlayCard(cardIdx) {\n// Extract `user.game` of `UserReducer` from redux\nconst { user: { game } } = this.props;\n// If it is an empty card, not going to do anything\nif (game.hand_player[cardIdx] === 0) {\nreturn;\n}\n// Send a request to API (blockchain) to play card with card index\n// And call `loadUser` again for react to render latest game status to UI\nreturn ApiService.playCard(cardIdx).then(()=>{\nreturn this.loadUser();\n});\n}\nrender() {\n// Extract data from user data of `UserReducer` from redux\nconst { user: { name, win_count, lost_count, game } } = this.props;\n// Flag to indicate if the game has started or not\n// By checking if the deckCard of AI is still 17 (max card)\nconst isGameStarted = game && game.deck_ai.length !== 17;\n// If game hasn't started, display `PlayerProfile`\n// If game has started, display `GameMat`, `Resolution`, `Info` screen\n//此次添加调用Resolution组件\nreturn (\n`<section className=\"Game\">`\n{ !isGameStarted ?\n<PlayerProfile\nname={ name }\nwinCount={ win_count }\nlostCount={ lost_count }\nonStartGame={ this.handleStartGame }\n/>\n:\n<div className=\"container\">\n<GameMat\ndeckCardCount={ game.deck_ai.length }\naiLife={ game.life_ai }\naiHandCards={ game.hand_ai }\naiName=\"COMPUTER\"\nplayerLife={ game.life_player }\nplayerHandCards={ game.hand_player }\nplayerName={ name }\nonPlayCard={ this.handlePlayCard }\n/>\n<Resolution\nstatus={ game.status }\naiCard={ game.selected_card_ai }\naiName=\"COMPUTER\"\naiLost={ game.life_lost_ai }\nplayerCard={ game.selected_card_player }\nplayerName={ name }\nplayerLost={ game.life_lost_player }\n/>\n<GameInfo\ndeckCardCount={ game.deck_ai.length }\nhandCardCount={ game.hand_ai.filter( x => x > 0 ).length }\n/>\n</div>\n}\n`</section>`\n)\n}\n}\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n// Map the following action to props\nconst mapDispatchToProps = {\nsetUser: UserAction.setUser,\n};\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(Game);\n\n4 测试代码\ncd /eos-work/frontend\nnpm start\n\n在浏览器中输入网址测试。\n此次,我没有清空上节课程的账号缓存,所以输入网址后直接跳转到对战界面。\n![eost12-03.png](https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost12-03.png)\n\n5 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\nEOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg\",\"https://cdn.steemitimages.com/DQmZy6MnaHV9LAQsE4Mw4PyxbHFvD4vdFBK8AyAymRZsAsU/eost12-01.png\",\"https://cdn.steemitimages.com/DQmVEXNYPbGCBpK9G6qTdZ1KX9xobFbKQWneE6RQPjFmFSN/eost12-02.jpg\",\"https://cdn.steemitimages.com/DQmXmijXrF1kF1NsJMz2pNhSpaso2JpNMiodtiX2VR8jYdu/eost12-03.png\"],\"links\":[\"https://api-kylin.eosasia.one\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-6/frontend/src/components/Game/components/Resolution\",\"https://battles.eos.io/tutorial/lesson5/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
fyrstikkenupvoted (1.00%) @eoswing / eos-ai
2018/12/19 10:25:00
voterfyrstikken
authoreoswing
permlinkeos-ai
weight100 (1.00%)
Transaction InfoBlock #28697465/Trx 323579a4ad0344f167133f37504be5dbe52ab15d
View Raw JSON Data
{
  "trx_id": "323579a4ad0344f167133f37504be5dbe52ab15d",
  "block": 28697465,
  "trx_in_block": 0,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-19T10:25:00",
  "op": [
    "vote",
    {
      "voter": "fyrstikken",
      "author": "eoswing",
      "permlink": "eos-ai",
      "weight": 100
    }
  ]
}
eoswingpublished a new post: eos-ai
2018/12/19 10:07:57
parent author
parent permlinkeos
authoreoswing
permlinkeos-ai
title手把手教你玩eos:卡牌游戏第五课——AI部分
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。本文是第十一篇。本篇教程主要学习卡牌游戏的AI对手策略编写。 0.2 学习内容 相关准备 智能合约代码编写和部署 测试代码 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 在本课中,我们将为对手AI设计四种策略。 在每轮出牌时,AI随机选择其中一种策略并决定要出哪张牌。 在本课程结束时,我们将有一个可对战的AI! 1.2 AI的四种策略 AI的四种策略分别是: 策略1:最大程度争取获胜。 AI Best Card Wins 策略2:最大程度防止失败。 AI Minimize Losses 策略3:最大程度伤害对手。 AI Points Tally 策略4:最大程度减少自己伤害。 AI Loss Prevention 策略1解读 AI Best Card Win 最大程度争取获胜。 强调选择一张最有可能获胜的牌。 为此,该策略采取以下加权方式: 当AI的伤害值大于玩家的伤害值的时候,记3分 当AI的伤害值等于玩家的伤害值的时候,记-1分 当AI的伤害值小于玩家的伤害值的时候,记-2分 具体算法如下图所示: ![eost11-01.png](https://cdn.steemitimages.com/DQmQ6S2VBE7358NK2BYbstUbqC3SVHbTt59dTXM49wJVeVu/eost11-01.png) 策略2解读 AI Minimize Losses 最大程度防止失败。 强调选择失败率最低的卡。 为此,该策略采取以下加权方式: 当AI的伤害值大于玩家的伤害值的时候,记1分 当AI的伤害值等于玩家的伤害值的时候,记-1分 当AI的伤害值小于玩家的伤害值的时候,记-4分 具体算法如下图所示: ![eost11-02.png](https://cdn.steemitimages.com/DQmPSAk5hkwiyMXSXAWNYEBm35hgQcHiVc3FvtPsCEzpsC5/eost11-02.png) 策略3解读 AI Points Tally 最大程度伤害对手。 强调选择造成最大伤害的牌。 为此,该策略采取以下加权方式: (玩家卡牌伤害值 + 元素兼容性)- (AI卡牌伤害值 + 元素兼容性)。 具体算法如下图所示: ![eost11-03.png](https://cdn.steemitimages.com/DQmUBmk9PVCLe3cBArwKC7j8T2YLZmVHD7B98Xy12tg52wy/eost11-03.png) 策略4解读 AI Loss Prevention 最大程度减少自己伤害。 强调确保最大限度的从该游戏中生存下来。 当AI剩余大量HP时,此策略不适用。只有当AI剩余小于或等于2 HP时才会选择此策略。 为此,该策略采取以下加权方式: 不会输掉游戏的牌,记为1。 会导致输掉游戏的牌,记为0。 具体算法如下图所示: ![eost11-04.png](https://cdn.steemitimages.com/DQmPvcShqY5Hg1xv8X6m7Hc4MMX7RKL3A7eCPb13LPC9kjC/eost11-04.png) 1.3 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入后端智能合约文件夹 cd /eos-work/contracts/cardgame 2 智能合约代码编写和部署 2.1 编写合约代码 打开cardgame.hpp文件: vi cardgame.hpp 编辑代码,添加代码如下: void draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand); //在上面代码行后添加如下代码 //===下面为添加代码=== int calculate_attack_point(const card& card1, const card& card2); int ai_best_card_win_strategy(const int ai_attack_point, const int player_attack_point); int ai_min_loss_strategy(const int ai_attack_point, const int player_attack_point); int ai_points_tally_strategy(const int ai_attack_point, const int player_attack_point); int ai_loss_prevention_strategy(const int8_t life_ai, const int ai_attack_point, const int player_attack_point); int calculate_ai_card_score(const int strategy_idx, const int8_t life_ai, const card& ai_card, const vector<uint8_t> hand_player); int ai_choose_card(const game& game_data); //====== 打开gameplay.cpp文件: vi gameplay.cpp 编辑代码,在代码行的最后面添加代码如下: //在代码行的最后添加如下代码 // Calculate the final attack point of a card after taking the elemental bonus into account int cardgame::calculate_attack_point(const card& card1, const card& card2) { int result = card1.attack_point; return result; // AI Best Card Win Strategy int cardgame::ai_best_card_win_strategy(const int ai_attack_point, const int player_attack_point) { eosio::print("Best Card Wins"); if (ai_attack_point > player_attack_point) return 3; if (ai_attack_point < player_attack_point) return -2; } 打开cardgame.cpp文件: vi cardgame.cpp 编辑代码,添加代码如下: game_data.hand_player[player_card_idx] = 0; //在上面代码行后添加如下代码 //===下面为添加代码=== // AI picks a card int ai_card_idx = ai_choose_card(game_data); game_data.selected_card_ai = game_data.hand_ai[ai_card_idx]; game_data.hand_ai[ai_card_idx] = 0; 2.2 部署智能合约覆盖原合约编译智能合约 编译wast文件 eosiocpp -o cardgame.wast cardgame.cpp 编译abi文件 eosiocpp -g cardgame.abi cardgame.cpp 解锁钱包 cleos wallet unlock -n gamewallet 部署智能合约 cleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active 至此,后端的合约重新部署完成。 3 测试代码 cd /eos-work/frontendnpm start 在浏览器中输入网址测试。 因为现在游戏并不完整,测试后遗留数据不方便清零。 所以每次阶段性查看下效果,最好新建一个账户测试。 此次测试,新建了一个账户cardgame2334。 登录游戏。 ![eost11-05.png](https://cdn.steemitimages.com/DQmRMn4TCu55zUirkNm3snpmqoejWBDoq4pYrUtBCw4w2dh/eost11-05.png) 进入游戏。 ![eost11-06.png](https://cdn.steemitimages.com/DQmesPcxJi9u1QPknwSm8UxzSAGizamy3C8xviaeB3qSm9E/eost11-06.png) 开始游戏。 ![eost11-07.png](https://cdn.steemitimages.com/DQmPfdCk92D7ofW5wVgugHfdDvnKccayd7Ayxo9XKi4VAxr/eost11-07.png) 出牌,同时AI出牌。 ![eost11-08.png](https://cdn.steemitimages.com/DQmc74f9oohA28Ya96auYC7d9VzfHapa5wdpEmfo2qcM7mt/eost11-08.png) 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg","https://cdn.steemitimages.com/DQmQ6S2VBE7358NK2BYbstUbqC3SVHbTt59dTXM49wJVeVu/eost11-01.png","https://cdn.steemitimages.com/DQmPSAk5hkwiyMXSXAWNYEBm35hgQcHiVc3FvtPsCEzpsC5/eost11-02.png","https://cdn.steemitimages.com/DQmUBmk9PVCLe3cBArwKC7j8T2YLZmVHD7B98Xy12tg52wy/eost11-03.png","https://cdn.steemitimages.com/DQmPvcShqY5Hg1xv8X6m7Hc4MMX7RKL3A7eCPb13LPC9kjC/eost11-04.png","https://cdn.steemitimages.com/DQmRMn4TCu55zUirkNm3snpmqoejWBDoq4pYrUtBCw4w2dh/eost11-05.png","https://cdn.steemitimages.com/DQmesPcxJi9u1QPknwSm8UxzSAGizamy3C8xviaeB3qSm9E/eost11-06.png","https://cdn.steemitimages.com/DQmPfdCk92D7ofW5wVgugHfdDvnKccayd7Ayxo9XKi4VAxr/eost11-07.png","https://cdn.steemitimages.com/DQmc74f9oohA28Ya96auYC7d9VzfHapa5wdpEmfo2qcM7mt/eost11-08.png"],"links":["https://api-kylin.eosasia.one","https://battles.eos.io/tutorial/lesson5/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #28697124/Trx ed41e2b894f28f0fedc21da2302ce1abbaaa1a22
View Raw JSON Data
{
  "trx_id": "ed41e2b894f28f0fedc21da2302ce1abbaaa1a22",
  "block": 28697124,
  "trx_in_block": 16,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-19T10:07:57",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-ai",
      "title": "手把手教你玩eos:卡牌游戏第五课——AI部分",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg)\n\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。本文是第十一篇。本篇教程主要学习卡牌游戏的AI对手策略编写。\n\n0.2 学习内容\n相关准备\n智能合约代码编写和部署\n测试代码\n0.3 机器环境\ncpu: 1核\n内存: 8G\n操作系统:CentOS 7.4 64位\n服务器所在地:香港\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n1 相关准备\n1.1 课程目标\n在本课中,我们将为对手AI设计四种策略。\n\n在每轮出牌时,AI随机选择其中一种策略并决定要出哪张牌。\n\n在本课程结束时,我们将有一个可对战的AI!\n\n1.2 AI的四种策略\nAI的四种策略分别是:\n\n策略1:最大程度争取获胜。 AI Best Card Wins\n\n策略2:最大程度防止失败。 AI Minimize Losses\n\n策略3:最大程度伤害对手。 AI Points Tally\n\n策略4:最大程度减少自己伤害。 AI Loss Prevention\n\n策略1解读\nAI Best Card Win 最大程度争取获胜。 强调选择一张最有可能获胜的牌。\n\n为此,该策略采取以下加权方式:\n\n当AI的伤害值大于玩家的伤害值的时候,记3分\n当AI的伤害值等于玩家的伤害值的时候,记-1分\n当AI的伤害值小于玩家的伤害值的时候,记-2分\n具体算法如下图所示:\n![eost11-01.png](https://cdn.steemitimages.com/DQmQ6S2VBE7358NK2BYbstUbqC3SVHbTt59dTXM49wJVeVu/eost11-01.png)\n\n策略2解读\nAI Minimize Losses 最大程度防止失败。 强调选择失败率最低的卡。\n\n为此,该策略采取以下加权方式:\n\n当AI的伤害值大于玩家的伤害值的时候,记1分\n当AI的伤害值等于玩家的伤害值的时候,记-1分\n当AI的伤害值小于玩家的伤害值的时候,记-4分\n具体算法如下图所示:\n![eost11-02.png](https://cdn.steemitimages.com/DQmPSAk5hkwiyMXSXAWNYEBm35hgQcHiVc3FvtPsCEzpsC5/eost11-02.png)\n\n策略3解读\nAI Points Tally 最大程度伤害对手。 强调选择造成最大伤害的牌。\n\n为此,该策略采取以下加权方式:\n\n(玩家卡牌伤害值 + 元素兼容性)- (AI卡牌伤害值 + 元素兼容性)。\n\n具体算法如下图所示:\n![eost11-03.png](https://cdn.steemitimages.com/DQmUBmk9PVCLe3cBArwKC7j8T2YLZmVHD7B98Xy12tg52wy/eost11-03.png)\n\n策略4解读\nAI Loss Prevention 最大程度减少自己伤害。 强调确保最大限度的从该游戏中生存下来。\n\n当AI剩余大量HP时,此策略不适用。只有当AI剩余小于或等于2 HP时才会选择此策略。\n\n为此,该策略采取以下加权方式:\n\n不会输掉游戏的牌,记为1。\n\n会导致输掉游戏的牌,记为0。\n\n具体算法如下图所示:\n![eost11-04.png](https://cdn.steemitimages.com/DQmPvcShqY5Hg1xv8X6m7Hc4MMX7RKL3A7eCPb13LPC9kjC/eost11-04.png)\n\n1.3 准备工作\n进入开发环境容器 docker exec -it eosdev /bin/bash\n\n进入后端智能合约文件夹 cd /eos-work/contracts/cardgame\n\n2 智能合约代码编写和部署 2.1 编写合约代码\n打开cardgame.hpp文件: vi cardgame.hpp\n\n编辑代码,添加代码如下:\n\nvoid draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand); //在上面代码行后添加如下代码 //===下面为添加代码===\n\nint calculate_attack_point(const card& card1, const card& card2);\n   int ai_best_card_win_strategy(const int ai_attack_point, const int player_attack_point);\n   int ai_min_loss_strategy(const int ai_attack_point, const int player_attack_point);\n   int ai_points_tally_strategy(const int ai_attack_point, const int player_attack_point);\n   int ai_loss_prevention_strategy(const int8_t life_ai, const int ai_attack_point, const int player_attack_point);\n   int calculate_ai_card_score(const int strategy_idx, const int8_t life_ai,\n                               const card& ai_card, const vector<uint8_t> hand_player);\n   int ai_choose_card(const game& game_data);\n//======\n打开gameplay.cpp文件: vi gameplay.cpp\n\n编辑代码,在代码行的最后面添加代码如下: //在代码行的最后添加如下代码\n\n// Calculate the final attack point of a card after taking the elemental bonus into account\nint cardgame::calculate_attack_point(const card& card1, const card& card2) {\n  int result = card1.attack_point;\n  return result;\n// AI Best Card Win Strategy\nint cardgame::ai_best_card_win_strategy(const int ai_attack_point, const int player_attack_point) {\n  eosio::print(\"Best Card Wins\");\n  if (ai_attack_point > player_attack_point) return 3;\n  if (ai_attack_point < player_attack_point) return -2;\n}\n打开cardgame.cpp文件: vi cardgame.cpp\n\n编辑代码,添加代码如下: game_data.hand_player[player_card_idx] = 0; //在上面代码行后添加如下代码 //===下面为添加代码=== // AI picks a card    int ai_card_idx = ai_choose_card(game_data);    game_data.selected_card_ai = game_data.hand_ai[ai_card_idx];    game_data.hand_ai[ai_card_idx] = 0;\n\n2.2 部署智能合约覆盖原合约编译智能合约\n编译wast文件 eosiocpp -o cardgame.wast cardgame.cpp 编译abi文件 eosiocpp -g cardgame.abi cardgame.cpp 解锁钱包 cleos wallet unlock -n gamewallet 部署智能合约 cleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active 至此,后端的合约重新部署完成。\n\n3 测试代码\ncd /eos-work/frontendnpm start\n\n在浏览器中输入网址测试。\n因为现在游戏并不完整,测试后遗留数据不方便清零。\n\n所以每次阶段性查看下效果,最好新建一个账户测试。\n\n此次测试,新建了一个账户cardgame2334。\n\n登录游戏。\n![eost11-05.png](https://cdn.steemitimages.com/DQmRMn4TCu55zUirkNm3snpmqoejWBDoq4pYrUtBCw4w2dh/eost11-05.png)\n\n进入游戏。\n![eost11-06.png](https://cdn.steemitimages.com/DQmesPcxJi9u1QPknwSm8UxzSAGizamy3C8xviaeB3qSm9E/eost11-06.png)\n\n\n开始游戏。\n![eost11-07.png](https://cdn.steemitimages.com/DQmPfdCk92D7ofW5wVgugHfdDvnKccayd7Ayxo9XKi4VAxr/eost11-07.png)\n\n\n出牌,同时AI出牌。\n![eost11-08.png](https://cdn.steemitimages.com/DQmc74f9oohA28Ya96auYC7d9VzfHapa5wdpEmfo2qcM7mt/eost11-08.png)\n\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\nEOS官方游戏开发第五课: https://battles.eos.io/tutorial/lesson5/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg\",\"https://cdn.steemitimages.com/DQmQ6S2VBE7358NK2BYbstUbqC3SVHbTt59dTXM49wJVeVu/eost11-01.png\",\"https://cdn.steemitimages.com/DQmPSAk5hkwiyMXSXAWNYEBm35hgQcHiVc3FvtPsCEzpsC5/eost11-02.png\",\"https://cdn.steemitimages.com/DQmUBmk9PVCLe3cBArwKC7j8T2YLZmVHD7B98Xy12tg52wy/eost11-03.png\",\"https://cdn.steemitimages.com/DQmPvcShqY5Hg1xv8X6m7Hc4MMX7RKL3A7eCPb13LPC9kjC/eost11-04.png\",\"https://cdn.steemitimages.com/DQmRMn4TCu55zUirkNm3snpmqoejWBDoq4pYrUtBCw4w2dh/eost11-05.png\",\"https://cdn.steemitimages.com/DQmesPcxJi9u1QPknwSm8UxzSAGizamy3C8xviaeB3qSm9E/eost11-06.png\",\"https://cdn.steemitimages.com/DQmPfdCk92D7ofW5wVgugHfdDvnKccayd7Ayxo9XKi4VAxr/eost11-07.png\",\"https://cdn.steemitimages.com/DQmc74f9oohA28Ya96auYC7d9VzfHapa5wdpEmfo2qcM7mt/eost11-08.png\"],\"links\":[\"https://api-kylin.eosasia.one\",\"https://battles.eos.io/tutorial/lesson5/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
councilupvoted (10.00%) @eoswing / 6vqt34-eos
2018/12/12 11:12:30
votercouncil
authoreoswing
permlink6vqt34-eos
weight1000 (10.00%)
Transaction InfoBlock #28496975/Trx 56e3ff2d12f5629579397b036cae8f56d3ca9561
View Raw JSON Data
{
  "trx_id": "56e3ff2d12f5629579397b036cae8f56d3ca9561",
  "block": 28496975,
  "trx_in_block": 2,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-12T11:12:30",
  "op": [
    "vote",
    {
      "voter": "council",
      "author": "eoswing",
      "permlink": "6vqt34-eos",
      "weight": 1000
    }
  ]
}
filipinoupvoted (10.00%) @eoswing / 6vqt34-eos
2018/12/12 10:51:45
voterfilipino
authoreoswing
permlink6vqt34-eos
weight1000 (10.00%)
Transaction InfoBlock #28496560/Trx 91e3c0152400346421a8d99b831ccc772171caea
View Raw JSON Data
{
  "trx_id": "91e3c0152400346421a8d99b831ccc772171caea",
  "block": 28496560,
  "trx_in_block": 9,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-12T10:51:45",
  "op": [
    "vote",
    {
      "voter": "filipino",
      "author": "eoswing",
      "permlink": "6vqt34-eos",
      "weight": 1000
    }
  ]
}
eoswingpublished a new post: 6vqt34-eos
2018/12/12 10:22:51
parent author
parent permlinkeos
authoreoswing
permlink6vqt34-eos
title手把手教你玩eos:卡牌游戏第四课——游戏核心组件
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第十篇。本篇教程主要学习卡牌游戏的核心代码编写。 0.2 学习内容 相关准备 智能合约代码编写和部署 编写前端代码 测试代码 0.3 机器环境 ●cpu: 1核 ●内存: 8G ●操作系统:CentOS 7.4 64位 ●服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 在本篇教程里,将介绍一些关键组件以及游戏的玩法。 我们在智能合同里定义的数据结构,包含用于显示前端信息的游戏状态。同时增加键屏幕组件GameInfo,GameMap,Handcards和PlayerInfo。 最后将这些前端组件拼接起来,以便玩家可以通过从UI调用智能合约操作来启动游戏并玩牌。 还介绍了一种简单但有效的随机化技术。 整个流程如下图所示: ![eost10-00.png](https://cdn.steemitimages.com/DQmRrhQx2JdHhZbdKi36eNm857iB8ismaRVZWSrwZNyz8ef/eost10-00.png) 1.2 游戏规则 两位玩家在开始时都以5HP开始。一旦某一玩家的HP下降到0,游戏结束。 每把游戏都有三个状态,即: ●ONGOING–游戏正在进行中。 ●PLAYER_WON–游戏已经结束且玩家获胜。 ●PLAYER_LOST–游戏已经结束且玩家失败。 游戏中的卡牌: ●Elemental Battles中有11张独特的牌 ●每张卡属于一种元素类型 ●每张卡都分配了攻击力 ●每个玩家都以相同的17张牌开始 一些元素类型具有元素兼容性 五种元素类型分别是: ![eost10-01.png](https://cdn.steemitimages.com/DQmNwUGUXis7vQvGBoZ1QzzgW8q4WvdEGDjtC2GxL7kBxRy/eost10-01.png) 卡片类型是元素类型和攻击力的组合。让我们看一下牌组中的所有牌: ![eost10-02.png](https://cdn.steemitimages.com/DQmduxoVviwzcReodDrYvSDu8xQH64a9rmVHxi6tzZdEbGu/eost10-02.png) 1.3 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入后端智能合约文件夹 cd /eos-work/contracts/cardgame 2 智能合约代码编写和部署 2.1 编写合约代码 打开cardgame.hpp文件: vi cardgame.hpp 编辑代码,最终代码如下: #include <eosiolib/eosio.hpp> using namespace std; class cardgame : public eosio::contract { private: enum game_status: int8_t { ONGOING = 0, PLAYER_WON = 1, PLAYER_LOST = -1 }; enum card_type: uint8_t { EMPTY = 0, // Represents empty slot in hand FIRE = 1, WOOD = 2, WATER = 3, NEUTRAL = 4, VOID = 5 }; struct card { uint8_t type; uint8_t attack_point; }; typedef uint8_t card_id; const map<card_id, card> card_dict = { { 0, {EMPTY, 0} }, { 1, {FIRE, 1} }, { 2, {FIRE, 1} }, { 3, {FIRE, 2} }, { 4, {FIRE, 2} }, { 5, {FIRE, 3} }, { 6, {WOOD, 1} }, { 7, {WOOD, 1} }, { 8, {WOOD, 2} }, { 9, {WOOD, 2} }, { 10, {WOOD, 3} }, { 11, {WATER, 1} }, { 12, {WATER, 1} }, { 13, {WATER, 2} }, { 14, {WATER, 2} }, { 15, {WATER, 3} }, { 16, {NEUTRAL, 3} }, { 17, {VOID, 0} } }; struct game { int8_t life_player = 5; int8_t life_ai = 5; vector<card_id> deck_player = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; vector<card_id> deck_ai = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; vector<card_id> hand_player = {0, 0, 0, 0}; vector<card_id> hand_ai = {0, 0, 0, 0}; card_id selected_card_player = 0; card_id selected_card_ai = 0; uint8_t life_lost_player = 0; uint8_t life_lost_ai = 0; int8_t status = ONGOING; }; // @abi table users struct user_info { account_name name; uint16_t win_count = 0; uint16_t lost_count = 0; game game_data; auto primary_key() const { return name; } }; // @abi table seed struct seed { uint64_t key = 1; uint32_t value = 1; auto primary_key() const { return key; } }; typedef eosio::multi_index<N(users), user_info> users_table; typedef eosio::multi_index<N(seed), seed> seed_table; users_table _users; seed_table _seed; void draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand); int random(const int range); public: cardgame( account_name self ):contract(self),_users(self, self),_seed(self, self){} void login(account_name username); void startgame(account_name username); void playcard(account_name username, uint8_t player_card_idx); }; 打开gameplay.cpp文件: vi gameplay.cpp 编辑代码,最终代码如下: #include "cardgame.hpp" // Simple Pseudo Random Number Algorithm, randomly pick a number within 0 to n-1 int cardgame::random(const int range) { // Find the existing seed auto seed_iterator = _seed.begin(); // Initialize the seed with default value if it is not found if (seed_iterator == _seed.end()) { seed_iterator = _seed.emplace( _self, [&]( auto& seed ) { }); } // Generate new seed value using the existing seed value int prime = 65537; auto new_seed_value = (seed_iterator->value + now()) % prime; // Store the updated seed value in the table _seed.modify( seed_iterator, _self, [&]( auto& s ) { s.value = new_seed_value; }); // Get the random result in desired range int random_result = new_seed_value % range; return random_result; } // Draw one card from the deck and assign it to the hand void cardgame::draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand) { // Pick a random card from the deck int deck_card_idx = random(deck.size()); // Find the first empty slot in the hand int first_empty_slot = -1; for (int i = 0; i <= hand.size(); i++) { auto id = hand[i]; if (card_dict.at(id).type == EMPTY) { first_empty_slot = i; break; } } eosio_assert(first_empty_slot != -1, "No empty slot in the player's hand"); // Assign the card to the first empty slot in the hand hand[first_empty_slot] = deck[deck_card_idx]; // Remove the card from the deck deck.erase(deck.begin() + deck_card_idx); } 打开cardgame.cpp文件: vi cardgame.cpp 编辑代码,最终代码如下: #include "gameplay.cpp" void cardgame::login(account_name username) { // Ensure this action is authorized by the player require_auth(username); // Create a record in the table if the player doesn't exist in our app yet auto user_iterator = _users.find(username); if (user_iterator == _users.end()) { user_iterator = _users.emplace(username, [&](auto& new_user) { new_user.name = username; }); } } void cardgame::startgame(account_name username) { // Ensure this action is authorized by the player require_auth(username); auto& user = _users.get(username, "User doesn't exist"); _users.modify(user, username, [&](auto& modified_user) { // Create a new game game game_data; // Draw 4 cards each for the player and the AI for (uint8_t i = 0; i < 4; i++) { draw_one_card(game_data.deck_player, game_data.hand_player); draw_one_card(game_data.deck_ai, game_data.hand_ai); } // Assign the newly created game to the player modified_user.game_data = game_data; }); } void cardgame::playcard(account_name username, uint8_t player_card_idx) { // Ensure this action is authorized by the player require_auth(username); // Checks that selected card is valid eosio_assert(player_card_idx < 4, "playcard: Invalid hand index"); auto& user = _users.get(username, "User doesn't exist"); // Verify game status is suitable for the player to play a card eosio_assert(user.game_data.status == ONGOING, "playcard: This game has ended. Please start a new one"); eosio_assert(user.game_data.selected_card_player == 0, "playcard: The player has played his card this turn!"); _users.modify(user, username, [&](auto& modified_user) { game& game_data = modified_user.game_data; // Assign the selected card from the player's hand game_data.selected_card_player = game_data.hand_player[player_card_idx]; game_data.hand_player[player_card_idx] = 0; }); } EOSIO_ABI(cardgame, (login)(startgame)(playcard)) 2.2 部署智能合约覆盖原合约 编译智能合约 编译wast文件 eosiocpp -o cardgame.wast cardgame.cpp 编译abi文件 eosiocpp -g cardgame.abi cardgame.cpp 解锁钱包 cleos wallet unlock -n gamewallet 命令行显示如下: ![eost10-03.png](https://cdn.steemitimages.com/DQmdZkBpEZYZLXLeuqzt6DxixKho4PsPWsdFEHvp5WLjXpx/eost10-03.png) 部署智能合约 cleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active 命令行输出如下: ![eost10-04.png](https://cdn.steemitimages.com/DQmNvkMzEDipp46JiuQGeVNYBkMKpGgkqYHSMi5EAH2uPRT/eost10-04.png) 至此,后端的合约重新部署完成。 3 编写前端代码 3.1 下载Game中五个组件代码 由于时间和篇幅关系,在这里只是下载代码,就不把代码贴出来一一解读了。 建议读者最好挨个下载,然后逐一查看代码逻辑。 cd /eos-work/frontend/src/components/Game/components/ svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/Card svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameInfo svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameMat svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/HandCards svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/PlayerInfo 3.2 整合组件 vi index.js 更新代码如下: import Card from './Card'; import GameInfo from './GameInfo'; import GameMat from './GameMat'; import HandCards from './HandCards'; import PlayerInfo from './PlayerInfo'; import PlayerProfile from './PlayerProfile'; export { Card, GameInfo, GameMat, HandCards, PlayerInfo, PlayerProfile, } 返回上一级,编辑Game.jsx cd .. vi Game.jsx 更新代码如下: // React core import React, { Component } from 'react'; import { connect } from 'react-redux'; // Game subcomponents import { GameInfo, GameMat, PlayerProfile } from './components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class Game extends Component { constructor(props) { // Inherit constructor super(props); // Bind functions this.loadUser = this.loadUser.bind(this); this.handleStartGame = this.handleStartGame.bind(this); this.handlePlayCard = this.handlePlayCard.bind(this); // Call `loadUser` before mounting the app this.loadUser(); } // Get latest user object from blockchain loadUser() { // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux const { setUser, user: { name } } = this.props; // Send request the blockchain by calling the ApiService, // Get the user object and store the `win_count`, `lost_count` and `game_data` object return ApiService.getUserByName(name).then(user => { setUser({ win_count: user.win_count, lost_count: user.lost_count, game: user.game_data, }); }); } handleStartGame() { // Send a request to API (blockchain) to start game // And call `loadUser` again for react to render latest game status to UI return ApiService.startGame().then(()=>{ return this.loadUser(); }); } handlePlayCard(cardIdx) { // Extract `user.game` of `UserReducer` from redux const { user: { game } } = this.props; // If it is an empty card, not going to do anything if (game.hand_player[cardIdx] === 0) { return; } // Send a request to API (blockchain) to play card with card index // And call `loadUser` again for react to render latest game status to UI return ApiService.playCard(cardIdx).then(()=>{ return this.loadUser(); }); } render() { // Extract data from user data of `UserReducer` from redux const { user: { name, win_count, lost_count, game } } = this.props; // Flag to indicate if the game has started or not // By checking if the deckCard of AI is still 17 (max card) const isGameStarted = game && game.deck_ai.length !== 17; // If game hasn't started, display `PlayerProfile` // If game has started, display `GameMat`, `Info` screen return ( <section className="Game"> { !isGameStarted ? <PlayerProfile name={ name } winCount={ win_count } lostCount={ lost_count } onStartGame={ this.handleStartGame } /> : <div className="container"> <GameMat deckCardCount={ game.deck_ai.length } aiLife={ game.life_ai } aiHandCards={ game.hand_ai } aiName="COMPUTER" playerLife={ game.life_player } playerHandCards={ game.hand_player } playerName={ name } onPlayCard={ this.handlePlayCard } /> <GameInfo deckCardCount={ game.deck_ai.length } handCardCount={ game.hand_ai.filter( x => x > 0 ).length } /> </div> } </section> ) } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(Game); 3.3 编辑与区块链交互的ApiService.js cd /eos-work/frontend/src/services/ vi ApiService.js 修改代码如下: import { Api, Rpc, SignatureProvider } from 'eosjs'; // Main action call to blockchain async function takeAction(action, dataValue) { const privateKey = localStorage.getItem("cardgame_key"); const rpc = new Rpc.JsonRpc(process.env.REACT_APP_EOS_HTTP_ENDPOINT); const signatureProvider = new SignatureProvider([privateKey]); const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() }); // Main call to blockchain after setting action, account_name and data try { const resultWithConfig = await api.transact({ actions: [{ account: process.env.REACT_APP_EOS_CONTRACT_NAME, name: action, authorization: [{ actor: localStorage.getItem("cardgame_account"), permission: 'active', }], data: dataValue, }] }, { blocksBehind: 3, expireSeconds: 30, }); return resultWithConfig; } catch (err) { throw(err) } } class ApiService { static getCurrentUser() { return new Promise((resolve, reject) => { if (!localStorage.getItem("cardgame_account")) { return reject(); } takeAction("login", { username: localStorage.getItem("cardgame_account") }) .then(() => { resolve(localStorage.getItem("cardgame_account")); }) .catch(err => { localStorage.removeItem("cardgame_account"); localStorage.removeItem("cardgame_key"); reject(err); }); }); } static login({ username, key }) { return new Promise((resolve, reject) => { localStorage.setItem("cardgame_account", username); localStorage.setItem("cardgame_key", key); takeAction("login", { username: username }) .then(() => { resolve(); }) .catch(err => { localStorage.removeItem("cardgame_account"); localStorage.removeItem("cardgame_key"); reject(err); }); }); } static startGame() { return takeAction("startgame", { username: localStorage.getItem("cardgame_account") }); } static playCard(cardIdx) { return takeAction("playcard", { username: localStorage.getItem("cardgame_account"), player_card_idx: cardIdx }); } static async getUserByName(username) { try { const rpc = new Rpc.JsonRpc(process.env.REACT_APP_EOS_HTTP_ENDPOINT); const result = await rpc.get_table_rows({ "json": true, "code": process.env.REACT_APP_EOS_CONTRACT_NAME, // contract who owns the table "scope": process.env.REACT_APP_EOS_CONTRACT_NAME, // scope of the table "table": "users", // name of the table as specified by the contract abi "limit": 1, "lower_bound": username, }); return result.rows[0]; } catch (err) { console.error(err); } } } export default ApiService; 4 测试代码 cd /eos-work/frontend npm start 在浏览器中输入网址测试。 我新建了一个账户cardgame2333,登录游戏。 ![eost10-05.png](https://cdn.steemitimages.com/DQmTCVM9wVDRxeYywr5UBDJ7UavV6RJrAQgth4QAcMAHHER/eost10-05.png) 进入游戏。 ![eost10-06.png](https://cdn.steemitimages.com/DQmTzDy6FARijrQSyWRighAq7Jyw6Z1bppt3zkcnUvbVS4a/eost10-06.png) 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第四课: https://battles.eos.io/tutorial/lesson4/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain","include"],"image":["https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg","https://cdn.steemitimages.com/DQmRrhQx2JdHhZbdKi36eNm857iB8ismaRVZWSrwZNyz8ef/eost10-00.png","https://cdn.steemitimages.com/DQmNwUGUXis7vQvGBoZ1QzzgW8q4WvdEGDjtC2GxL7kBxRy/eost10-01.png","https://cdn.steemitimages.com/DQmduxoVviwzcReodDrYvSDu8xQH64a9rmVHxi6tzZdEbGu/eost10-02.png","https://cdn.steemitimages.com/DQmdZkBpEZYZLXLeuqzt6DxixKho4PsPWsdFEHvp5WLjXpx/eost10-03.png","https://cdn.steemitimages.com/DQmNvkMzEDipp46JiuQGeVNYBkMKpGgkqYHSMi5EAH2uPRT/eost10-04.png","https://cdn.steemitimages.com/DQmTCVM9wVDRxeYywr5UBDJ7UavV6RJrAQgth4QAcMAHHER/eost10-05.png","https://cdn.steemitimages.com/DQmTzDy6FARijrQSyWRighAq7Jyw6Z1bppt3zkcnUvbVS4a/eost10-06.png"],"links":["https://api-kylin.eosasia.one","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/Card","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameInfo","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameMat","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/HandCards","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/PlayerInfo","https://battles.eos.io/tutorial/lesson4/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #28495982/Trx 11545ef671ccfd36941e4ea8676bc21af33bed70
View Raw JSON Data
{
  "trx_id": "11545ef671ccfd36941e4ea8676bc21af33bed70",
  "block": 28495982,
  "trx_in_block": 14,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-12T10:22:51",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "6vqt34-eos",
      "title": "手把手教你玩eos:卡牌游戏第四课——游戏核心组件",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第十篇。本篇教程主要学习卡牌游戏的核心代码编写。\n\n0.2 学习内容\n相关准备\n智能合约代码编写和部署\n编写前端代码\n测试代码\n\n0.3 机器环境\n●cpu: 1核\n●内存: 8G\n●操作系统:CentOS 7.4 64位\n●服务器所在地:香港\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n1 相关准备\n1.1 课程目标\n在本篇教程里,将介绍一些关键组件以及游戏的玩法。\n我们在智能合同里定义的数据结构,包含用于显示前端信息的游戏状态。同时增加键屏幕组件GameInfo,GameMap,Handcards和PlayerInfo。\n最后将这些前端组件拼接起来,以便玩家可以通过从UI调用智能合约操作来启动游戏并玩牌。\n\n还介绍了一种简单但有效的随机化技术。\n\n整个流程如下图所示:\n![eost10-00.png](https://cdn.steemitimages.com/DQmRrhQx2JdHhZbdKi36eNm857iB8ismaRVZWSrwZNyz8ef/eost10-00.png)\n\n1.2 游戏规则\n两位玩家在开始时都以5HP开始。一旦某一玩家的HP下降到0,游戏结束。\n\n每把游戏都有三个状态,即:\n●ONGOING–游戏正在进行中。\n●PLAYER_WON–游戏已经结束且玩家获胜。\n●PLAYER_LOST–游戏已经结束且玩家失败。\n\n游戏中的卡牌:\n●Elemental Battles中有11张独特的牌\n●每张卡属于一种元素类型\n●每张卡都分配了攻击力\n●每个玩家都以相同的17张牌开始\n\n一些元素类型具有元素兼容性\n\n五种元素类型分别是:\n![eost10-01.png](https://cdn.steemitimages.com/DQmNwUGUXis7vQvGBoZ1QzzgW8q4WvdEGDjtC2GxL7kBxRy/eost10-01.png)\n\n卡片类型是元素类型和攻击力的组合。让我们看一下牌组中的所有牌:\n![eost10-02.png](https://cdn.steemitimages.com/DQmduxoVviwzcReodDrYvSDu8xQH64a9rmVHxi6tzZdEbGu/eost10-02.png)\n\n1.3 准备工作\n进入开发环境容器\n\ndocker exec -it eosdev /bin/bash\n进入后端智能合约文件夹\n\ncd /eos-work/contracts/cardgame\n\n2 智能合约代码编写和部署\n2.1 编写合约代码\n打开cardgame.hpp文件:\n\n\nvi cardgame.hpp\n编辑代码,最终代码如下:\n\n#include <eosiolib/eosio.hpp>\n\nusing namespace std;\nclass cardgame : public eosio::contract {\n\n  private:\n\n    enum game_status: int8_t  {\n      ONGOING     = 0,\n      PLAYER_WON   = 1,\n      PLAYER_LOST  = -1\n    };\n\n    enum card_type: uint8_t {\n      EMPTY = 0, // Represents empty slot in hand\n      FIRE = 1,\n      WOOD = 2,\n      WATER = 3,\n      NEUTRAL = 4,\n      VOID = 5\n    };\n\n    struct card {\n      uint8_t type;\n      uint8_t attack_point;\n    };\n\n    typedef uint8_t card_id;\n\n    const map<card_id, card> card_dict = {\n      { 0, {EMPTY, 0} },\n      { 1, {FIRE, 1} },\n      { 2, {FIRE, 1} },\n      { 3, {FIRE, 2} },\n      { 4, {FIRE, 2} },\n      { 5, {FIRE, 3} },\n      { 6, {WOOD, 1} },\n      { 7, {WOOD, 1} },\n      { 8, {WOOD, 2} },\n      { 9, {WOOD, 2} },\n      { 10, {WOOD, 3} },\n      { 11, {WATER, 1} },\n      { 12, {WATER, 1} },\n      { 13, {WATER, 2} },\n      { 14, {WATER, 2} },\n      { 15, {WATER, 3} },\n      { 16, {NEUTRAL, 3} },\n      { 17, {VOID, 0} }\n    };\n\n    struct game {\n      int8_t          life_player = 5;\n      int8_t          life_ai = 5;\n      vector<card_id> deck_player = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};\n      vector<card_id> deck_ai = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};\n      vector<card_id> hand_player = {0, 0, 0, 0};\n      vector<card_id> hand_ai = {0, 0, 0, 0};\n      card_id         selected_card_player = 0;\n      card_id         selected_card_ai = 0;\n      uint8_t         life_lost_player = 0;\n      uint8_t         life_lost_ai = 0;\n      int8_t          status = ONGOING;\n    };\n\n    // @abi table users\n    struct user_info {\n      account_name    name;\n      uint16_t        win_count = 0;\n      uint16_t        lost_count = 0;\n      game            game_data;\n\n      auto primary_key() const { return name; }\n    };\n\n    // @abi table seed\n    struct seed {\n      uint64_t        key = 1;\n      uint32_t        value = 1;\n\n      auto primary_key() const { return key; }\n    };\n\n    typedef eosio::multi_index<N(users), user_info> users_table;\n\n    typedef eosio::multi_index<N(seed), seed> seed_table;\n\n    users_table _users;\n\n    seed_table _seed;\n\n    void draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand);\n\n    int random(const int range);\n\n  public:\n\n    cardgame( account_name self ):contract(self),_users(self, self),_seed(self, self){}\n\n    void login(account_name username);\n\n    void startgame(account_name username);\n\n    void playcard(account_name username, uint8_t player_card_idx);\n\n};\n打开gameplay.cpp文件:\n\nvi gameplay.cpp\n编辑代码,最终代码如下:\n\n#include \"cardgame.hpp\"\n\n// Simple Pseudo Random Number Algorithm, randomly pick a number within 0 to n-1\nint cardgame::random(const int range) {\n  // Find the existing seed\n  auto seed_iterator = _seed.begin();\n\n  // Initialize the seed with default value if it is not found\n  if (seed_iterator == _seed.end()) {\n    seed_iterator = _seed.emplace( _self, [&]( auto& seed ) { });\n  }\n\n  // Generate new seed value using the existing seed value\n  int prime = 65537;\n  auto new_seed_value = (seed_iterator->value + now()) % prime;\n\n  // Store the updated seed value in the table\n  _seed.modify( seed_iterator, _self, [&]( auto& s ) {\n    s.value = new_seed_value;\n  });\n\n  // Get the random result in desired range\n  int random_result = new_seed_value % range;\n  return random_result;\n}\n\n// Draw one card from the deck and assign it to the hand\nvoid cardgame::draw_one_card(vector<uint8_t>& deck, vector<uint8_t>& hand) {\n  // Pick a random card from the deck\n  int deck_card_idx = random(deck.size());\n\n  // Find the first empty slot in the hand\n  int first_empty_slot = -1;\n  for (int i = 0; i <= hand.size(); i++) {\n    auto id = hand[i];\n    if (card_dict.at(id).type == EMPTY) {\n      first_empty_slot = i;\n      break;\n    }\n  }\n  eosio_assert(first_empty_slot != -1, \"No empty slot in the player's hand\");\n\n  // Assign the card to the first empty slot in the hand\n  hand[first_empty_slot] = deck[deck_card_idx];\n\n  // Remove the card from the deck\n  deck.erase(deck.begin() + deck_card_idx);\n}\n打开cardgame.cpp文件:\n\nvi cardgame.cpp\n编辑代码,最终代码如下:\n\n#include \"gameplay.cpp\"\n\nvoid cardgame::login(account_name username) {\n  // Ensure this action is authorized by the player\n  require_auth(username);\n\n  // Create a record in the table if the player doesn't exist in our app yet\n  auto user_iterator = _users.find(username);\n  if (user_iterator == _users.end()) {\n    user_iterator = _users.emplace(username,  [&](auto& new_user) {\n      new_user.name = username;\n    });\n  }\n}\n\nvoid cardgame::startgame(account_name username) {\n  // Ensure this action is authorized by the player\n  require_auth(username);\n\n  auto& user = _users.get(username, \"User doesn't exist\");\n\n  _users.modify(user, username, [&](auto& modified_user) {\n    // Create a new game\n    game game_data;\n\n    // Draw 4 cards each for the player and the AI\n    for (uint8_t i = 0; i < 4; i++) {\n      draw_one_card(game_data.deck_player, game_data.hand_player);\n      draw_one_card(game_data.deck_ai, game_data.hand_ai);\n    }\n\n    // Assign the newly created game to the player\n    modified_user.game_data = game_data;\n  });\n}\n\nvoid cardgame::playcard(account_name username, uint8_t player_card_idx) {\n  // Ensure this action is authorized by the player\n  require_auth(username);\n\n  // Checks that selected card is valid\n  eosio_assert(player_card_idx < 4, \"playcard: Invalid hand index\");\n\n  auto& user = _users.get(username, \"User doesn't exist\");\n\n  // Verify game status is suitable for the player to play a card\n  eosio_assert(user.game_data.status == ONGOING,\n               \"playcard: This game has ended. Please start a new one\");\n  eosio_assert(user.game_data.selected_card_player == 0,\n               \"playcard: The player has played his card this turn!\");\n\n  _users.modify(user, username, [&](auto& modified_user) {\n    game& game_data = modified_user.game_data;\n\n    // Assign the selected card from the player's hand\n    game_data.selected_card_player = game_data.hand_player[player_card_idx];\n    game_data.hand_player[player_card_idx] = 0;\n  });\n}\n\nEOSIO_ABI(cardgame, (login)(startgame)(playcard))\n\n2.2 部署智能合约覆盖原合约\n编译智能合约\n编译wast文件\n\neosiocpp -o cardgame.wast cardgame.cpp\n编译abi文件\n\neosiocpp -g cardgame.abi cardgame.cpp\n解锁钱包\n\ncleos wallet unlock -n gamewallet\n命令行显示如下:\n![eost10-03.png](https://cdn.steemitimages.com/DQmdZkBpEZYZLXLeuqzt6DxixKho4PsPWsdFEHvp5WLjXpx/eost10-03.png)\n\n部署智能合约\n\ncleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active\n命令行输出如下:\n![eost10-04.png](https://cdn.steemitimages.com/DQmNvkMzEDipp46JiuQGeVNYBkMKpGgkqYHSMi5EAH2uPRT/eost10-04.png)\n至此,后端的合约重新部署完成。\n\n3 编写前端代码\n3.1 下载Game中五个组件代码\n由于时间和篇幅关系,在这里只是下载代码,就不把代码贴出来一一解读了。\n建议读者最好挨个下载,然后逐一查看代码逻辑。\n\ncd /eos-work/frontend/src/components/Game/components/\t\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/Card\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameInfo\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameMat\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/HandCards\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/PlayerInfo\n\n3.2 整合组件\n\nvi index.js\n更新代码如下:\n\t\nimport Card from './Card';\nimport GameInfo from './GameInfo';\nimport GameMat from './GameMat';\nimport HandCards from './HandCards';\nimport PlayerInfo from './PlayerInfo';\nimport PlayerProfile from './PlayerProfile';\n\nexport {\n  Card,\n  GameInfo,\n  GameMat,\n  HandCards,\n  PlayerInfo,\n  PlayerProfile,\n}\n返回上一级,编辑Game.jsx\n\ncd ..\n\nvi Game.jsx\n更新代码如下:\n\n// React core\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Game subcomponents\nimport { GameInfo, GameMat, PlayerProfile } from './components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services';\n\nclass Game extends Component {\n\n  constructor(props) {\n    // Inherit constructor\n    super(props);\n    // Bind functions\n    this.loadUser = this.loadUser.bind(this);\n    this.handleStartGame = this.handleStartGame.bind(this);\n    this.handlePlayCard = this.handlePlayCard.bind(this);\n    // Call `loadUser` before mounting the app\n    this.loadUser();\n  }\n\n  // Get latest user object from blockchain\n  loadUser() {\n    // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux\n    const { setUser, user: { name } } = this.props;\n    // Send request the blockchain by calling the ApiService,\n    // Get the user object and store the `win_count`, `lost_count` and `game_data` object\n    return ApiService.getUserByName(name).then(user => {\n      setUser({\n        win_count: user.win_count,\n        lost_count: user.lost_count,\n        game: user.game_data,\n      });\n    });\n  }\n\n  handleStartGame() {\n    // Send a request to API (blockchain) to start game\n    // And call `loadUser` again for react to render latest game status to UI\n    return ApiService.startGame().then(()=>{\n      return this.loadUser();\n    });\n  }\n\n  handlePlayCard(cardIdx) {\n    // Extract `user.game` of `UserReducer` from redux\n    const { user: { game } } = this.props;\n\n    // If it is an empty card, not going to do anything\n    if (game.hand_player[cardIdx] === 0) {\n      return;\n    }\n\n    // Send a request to API (blockchain) to play card with card index\n    // And call `loadUser` again for react to render latest game status to UI\n    return ApiService.playCard(cardIdx).then(()=>{\n      return this.loadUser();\n    });\n  }\n\n  render() {\n    // Extract data from user data of `UserReducer` from redux\n    const { user: { name, win_count, lost_count, game } } = this.props;\n\n    // Flag to indicate if the game has started or not\n    // By checking if the deckCard of AI is still 17 (max card)\n    const isGameStarted = game && game.deck_ai.length !== 17;\n\n    // If game hasn't started, display `PlayerProfile`\n    // If game has started, display `GameMat`, `Info` screen\n    return (\n      <section className=\"Game\">\n        { !isGameStarted ?\n            <PlayerProfile\n              name={ name }\n              winCount={ win_count }\n              lostCount={ lost_count }\n              onStartGame={ this.handleStartGame }\n            />\n          :\n            <div className=\"container\">\n              <GameMat\n                deckCardCount={ game.deck_ai.length }\n                aiLife={ game.life_ai }\n                aiHandCards={ game.hand_ai }\n                aiName=\"COMPUTER\"\n                playerLife={ game.life_player }\n                playerHandCards={ game.hand_player }\n                playerName={ name }\n                onPlayCard={ this.handlePlayCard }\n              />\n              <GameInfo\n                deckCardCount={ game.deck_ai.length }\n                handCardCount={ game.hand_ai.filter( x => x > 0 ).length }\n              />\n            </div>\n        }\n      </section>\n    )\n  }\n\n}\n\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n\n// Map the following action to props\nconst mapDispatchToProps = {\n  setUser: UserAction.setUser,\n};\n\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(Game);\n3.3 编辑与区块链交互的ApiService.js\n\ncd /eos-work/frontend/src/services/\n    \nvi ApiService.js\n修改代码如下:\n\nimport { Api, Rpc, SignatureProvider } from 'eosjs';\n\n// Main action call to blockchain\nasync function takeAction(action, dataValue) {\n  const privateKey = localStorage.getItem(\"cardgame_key\");\n  const rpc = new Rpc.JsonRpc(process.env.REACT_APP_EOS_HTTP_ENDPOINT);\n  const signatureProvider = new SignatureProvider([privateKey]);\n  const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });\n\n  // Main call to blockchain after setting action, account_name and data\n  try {\n    const resultWithConfig = await api.transact({\n      actions: [{\n        account: process.env.REACT_APP_EOS_CONTRACT_NAME,\n        name: action,\n        authorization: [{\n          actor: localStorage.getItem(\"cardgame_account\"),\n          permission: 'active',\n        }],\n        data: dataValue,\n      }]\n    }, {\n      blocksBehind: 3,\n      expireSeconds: 30,\n    });\n    return resultWithConfig;\n  } catch (err) {\n    throw(err)\n  }\n}\n\nclass ApiService {\n\n  static getCurrentUser() {\n    return new Promise((resolve, reject) => {\n      if (!localStorage.getItem(\"cardgame_account\")) {\n        return reject();\n      }\n      takeAction(\"login\", { username: localStorage.getItem(\"cardgame_account\") })\n        .then(() => {\n          resolve(localStorage.getItem(\"cardgame_account\"));\n        })\n        .catch(err => {\n          localStorage.removeItem(\"cardgame_account\");\n          localStorage.removeItem(\"cardgame_key\");\n          reject(err);\n        });\n    });\n  }\n\n  static login({ username, key }) {\n    return new Promise((resolve, reject) => {\n      localStorage.setItem(\"cardgame_account\", username);\n      localStorage.setItem(\"cardgame_key\", key);\n      takeAction(\"login\", { username: username })\n        .then(() => {\n          resolve();\n        })\n        .catch(err => {\n          localStorage.removeItem(\"cardgame_account\");\n          localStorage.removeItem(\"cardgame_key\");\n          reject(err);\n        });\n    });\n  }\n\n  static startGame() {\n    return takeAction(\"startgame\", { username: localStorage.getItem(\"cardgame_account\") });\n  }\n\n  static playCard(cardIdx) {\n    return takeAction(\"playcard\", { username: localStorage.getItem(\"cardgame_account\"), player_card_idx: cardIdx });\n  }\n\n  static async getUserByName(username) {\n    try {\n      const rpc = new Rpc.JsonRpc(process.env.REACT_APP_EOS_HTTP_ENDPOINT);\n      const result = await rpc.get_table_rows({\n        \"json\": true,\n        \"code\": process.env.REACT_APP_EOS_CONTRACT_NAME,    // contract who owns the table\n        \"scope\": process.env.REACT_APP_EOS_CONTRACT_NAME,   // scope of the table\n        \"table\": \"users\",    // name of the table as specified by the contract abi\n        \"limit\": 1,\n        \"lower_bound\": username,\n      });\n      return result.rows[0];\n    } catch (err) {\n      console.error(err);\n    }\n  }\n\n}\n\nexport default ApiService;\n\n4 测试代码\ncd /eos-work/frontend\n\nnpm start\n在浏览器中输入网址测试。\n我新建了一个账户cardgame2333,登录游戏。\n![eost10-05.png](https://cdn.steemitimages.com/DQmTCVM9wVDRxeYywr5UBDJ7UavV6RJrAQgth4QAcMAHHER/eost10-05.png)\n\n进入游戏。\n![eost10-06.png](https://cdn.steemitimages.com/DQmTzDy6FARijrQSyWRighAq7Jyw6Z1bppt3zkcnUvbVS4a/eost10-06.png)\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\nEOS官方游戏开发第四课: https://battles.eos.io/tutorial/lesson4/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\",\"include\"],\"image\":[\"https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg\",\"https://cdn.steemitimages.com/DQmRrhQx2JdHhZbdKi36eNm857iB8ismaRVZWSrwZNyz8ef/eost10-00.png\",\"https://cdn.steemitimages.com/DQmNwUGUXis7vQvGBoZ1QzzgW8q4WvdEGDjtC2GxL7kBxRy/eost10-01.png\",\"https://cdn.steemitimages.com/DQmduxoVviwzcReodDrYvSDu8xQH64a9rmVHxi6tzZdEbGu/eost10-02.png\",\"https://cdn.steemitimages.com/DQmdZkBpEZYZLXLeuqzt6DxixKho4PsPWsdFEHvp5WLjXpx/eost10-03.png\",\"https://cdn.steemitimages.com/DQmNvkMzEDipp46JiuQGeVNYBkMKpGgkqYHSMi5EAH2uPRT/eost10-04.png\",\"https://cdn.steemitimages.com/DQmTCVM9wVDRxeYywr5UBDJ7UavV6RJrAQgth4QAcMAHHER/eost10-05.png\",\"https://cdn.steemitimages.com/DQmTzDy6FARijrQSyWRighAq7Jyw6Z1bppt3zkcnUvbVS4a/eost10-06.png\"],\"links\":[\"https://api-kylin.eosasia.one\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/Card\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameInfo\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/GameMat\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/HandCards\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-4/frontend/src/components/Game/components/PlayerInfo\",\"https://battles.eos.io/tutorial/lesson4/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
yeheyupvoted (10.00%) @eoswing / 4srm5g-eos
2018/12/05 10:03:27
voteryehey
authoreoswing
permlink4srm5g-eos
weight1000 (10.00%)
Transaction InfoBlock #28294123/Trx 50c0981541bc49a5162e156ecb93fddbeda4dbe6
View Raw JSON Data
{
  "trx_id": "50c0981541bc49a5162e156ecb93fddbeda4dbe6",
  "block": 28294123,
  "trx_in_block": 6,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T10:03:27",
  "op": [
    "vote",
    {
      "voter": "yehey",
      "author": "eoswing",
      "permlink": "4srm5g-eos",
      "weight": 1000
    }
  ]
}
i0y090upvoted (100.00%) @eoswing / 4srm5g-eos
2018/12/05 09:37:57
voteri0y090
authoreoswing
permlink4srm5g-eos
weight10000 (100.00%)
Transaction InfoBlock #28293613/Trx 8d1c000bdd42f1459963cfa37c344b4175b48516
View Raw JSON Data
{
  "trx_id": "8d1c000bdd42f1459963cfa37c344b4175b48516",
  "block": 28293613,
  "trx_in_block": 0,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:37:57",
  "op": [
    "vote",
    {
      "voter": "i0y090",
      "author": "eoswing",
      "permlink": "4srm5g-eos",
      "weight": 10000
    }
  ]
}
devsupupvoted (0.69%) @eoswing / 4srm5g-eos
2018/12/05 09:37:24
voterdevsup
authoreoswing
permlink4srm5g-eos
weight69 (0.69%)
Transaction InfoBlock #28293602/Trx 9c55c9f0e555304d0f9e4c4a904618068d213908
View Raw JSON Data
{
  "trx_id": "9c55c9f0e555304d0f9e4c4a904618068d213908",
  "block": 28293602,
  "trx_in_block": 23,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:37:24",
  "op": [
    "vote",
    {
      "voter": "devsup",
      "author": "eoswing",
      "permlink": "4srm5g-eos",
      "weight": 69
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 4srm5g-eos
2018/12/05 09:23:21
votereoswing
authoreoswing
permlink4srm5g-eos
weight10000 (100.00%)
Transaction InfoBlock #28293321/Trx a063c2c88cb31a0701b86f3ac0acddf290fc564e
View Raw JSON Data
{
  "trx_id": "a063c2c88cb31a0701b86f3ac0acddf290fc564e",
  "block": 28293321,
  "trx_in_block": 5,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:23:21",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "4srm5g-eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 7crwnd-eos
2018/12/05 09:23:18
votereoswing
authoreoswing
permlink7crwnd-eos
weight10000 (100.00%)
Transaction InfoBlock #28293320/Trx c2d6e02147f2e5d8d592fa93a2d0db7a49cc9a0f
View Raw JSON Data
{
  "trx_id": "c2d6e02147f2e5d8d592fa93a2d0db7a49cc9a0f",
  "block": 28293320,
  "trx_in_block": 25,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:23:18",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "7crwnd-eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 2gojt3-eos
2018/12/05 09:23:15
votereoswing
authoreoswing
permlink2gojt3-eos
weight10000 (100.00%)
Transaction InfoBlock #28293319/Trx 147cf4be0df6f7c6f7df09bbd55e647fe4f975e8
View Raw JSON Data
{
  "trx_id": "147cf4be0df6f7c6f7df09bbd55e647fe4f975e8",
  "block": 28293319,
  "trx_in_block": 11,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:23:15",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "2gojt3-eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / eos-eos
2018/12/05 09:23:06
votereoswing
authoreoswing
permlinkeos-eos
weight10000 (100.00%)
Transaction InfoBlock #28293316/Trx 0f5e12b72e963980317195690132f988dd7f3470
View Raw JSON Data
{
  "trx_id": "0f5e12b72e963980317195690132f988dd7f3470",
  "block": 28293316,
  "trx_in_block": 0,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:23:06",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "eos-eos",
      "weight": 10000
    }
  ]
}
eoswingpublished a new post: 4srm5g-eos
2018/12/05 09:22:27
parent author
parent permlinkeos
authoreoswing
permlink4srm5g-eos
title手把手教你玩eos:卡牌游戏第三课——从区块链中读取状态
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第九篇。本篇教程主要学习如何从区块链中获取数据。 0.2 学习内容 相关准备 代码编写 测试代码 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 为了获取数据,我们使用RPC调用(get_table_rows)传入参数,这将强制它仅返回与包含在多索引表的一行中的当前播放器相关联的数据。然后,我们将在新的个人资料页面中显示前端的数据。 整个流程如下图所示: ![eost09-01.png](https://cdn.steemitimages.com/DQmZ3rqhYhhoPkVcdnwWsKSqsZonea3kbRni1U8muCy24so/eost09-01.png) 1.2 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入前端文件夹 cd /eos-work/frontend/src 2 代码编写 2.1 编写与区块链通信的代码 打开负责与后端区块链通信的ApiService.js vi ./services/ApiService.js 在代码中添加getUserByName()和getCurrentUser()两个函数: class ApiService { //===添加getCurrentUser()函数=== static getCurrentUser() { return new Promise((resolve, reject) => { if (!localStorage.getItem("cardgame_account")) { return reject(); } takeAction("login", { username: localStorage.getItem("cardgame_account") }) .then(() => { resolve(localStorage.getItem("cardgame_account")); }) .catch(err => { localStorage.removeItem("cardgame_account"); localStorage.removeItem("cardgame_key"); reject(err); }); }); } //===添加getUserByName()函数=== static async getUserByName(username) { try { const rpc = new Rpc.JsonRpc(process.env.REACT_APP_EOS_HTTP_ENDPOINT); const result = await rpc.get_table_rows({ "json": true, "code": process.env.REACT_APP_EOS_CONTRACT_NAME, // contract who owns the table "scope": process.env.REACT_APP_EOS_CONTRACT_NAME, // scope of the table "table": "users", // name of the table as specified by the contract abi "limit": 1, "lower_bound": username, }); return result.rows[0]; } catch (err) { console.error(err); } } //====== } 2.2 编写显示玩家信息的组件 我们在Game下面创建PlayerProfile组件负责显示玩家信息 首先,下载图片素材到images文件夹 cd ./components/Game/components/PlayerProfile/ svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-3/frontend/src/components/Game/components/PlayerProfile/images 创建PlayerProfile.jsx vi PlayerProfile.jsx 输入代码: import React, { Component } from 'react'; import { Button } from 'components'; class PlayerProfile extends Component { render() { // Extract data and event functions from props const { name, winCount, lostCount, onStartGame } = this.props; // Display welcome message, // buttons for login / start game, // number of winning and losing return ( <div className="PlayerProfile"> <div className="title">Elemental Battles - powered by EOSIO</div> <div className="welcome"> <span>Welcome</span> </div> <div className="username"> <span>{ name }</span> </div> <div className="record"> <p>Your Current Record</p> <span>Win <span className="count">{ winCount }</span></span> <span> | </span> <span>Lost <span className="count">{ lostCount }</span></span> </div> <div className="buttons"> <Button onClick={ onStartGame } className="green">START</Button> </div> </div> ) } } export default PlayerProfile; 创建index.js vi index.js 输入代码: import './PlayerProfile.css'; import PlayerProfile from './PlayerProfile'; export default PlayerProfile; 2.3 添加调用逻辑代码 回到上级目录,创建组件的index.js cd .. vi index.js 输入代码: import PlayerProfile from './PlayerProfile'; export { PlayerProfile, } 再回到Game目录下,在Game.jsx中增加代码块 cd .. vi Game.jsx 修改代码如下: // React core import React, { Component } from 'react'; import { connect } from 'react-redux'; // Game subcomponents import { PlayerProfile } from './components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class Game extends Component { constructor(props) { // Inherit constructor super(props); // Bind functions this.loadUser = this.loadUser.bind(this); // Call `loadUser` before mounting the app this.loadUser(); } // Get latest user object from blockchain loadUser() { // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux const { setUser, user: { name } } = this.props; // Send request the blockchain by calling the ApiService, // Get the user object and store the `win_count`, `lost_count` and `game_data` object return ApiService.getUserByName(name).then(user => { setUser({ win_count: user.win_count, lost_count: user.lost_count, game: user.game_data, }); }); } render() { // Extract data from user data of `UserReducer` from redux const { user: { name, win_count, lost_count } } = this.props; return ( <section className="Game"> <PlayerProfile name={ name } winCount={ win_count } lostCount={ lost_count } /> </section> ) } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(Game); 再到App文件夹下,修改App.jsx cd ../App vi App.jsx 此次修改如下,注意对比前后差别。 // React core import React, { Component } from 'react'; import { connect } from 'react-redux'; // Components import { Game, Login } from 'components'; // Services and redux action import { UserAction } from 'actions'; import { ApiService } from 'services'; class App extends Component { constructor(props) { // Inherit constructor super(props); // Bind functions this.getCurrentUser = this.getCurrentUser.bind(this); // Call getCurrentUser before mounting the app this.getCurrentUser(); } getCurrentUser() { // Extract setUser of UserAction from redux const { setUser } = this.props; // Send a request to API (blockchain) to get the current logged in user return ApiService.getCurrentUser() // If the server return a username .then(username => { // Save the username to redux store // For structure, ref: ./frontend/src/reducers/UserReducer.js setUser({ name: username }); }) // To ignore 401 console error .catch(() => {}); } render() { // Extract data from state and props (`user` is from redux) const { user: { name } } = this.props; // If the username is set in redux, display the Game component // If the username is NOT set in redux, display the Login component return ( <div className="App"> { name && <Game /> } { !name && <Login /> } </div> ); } } // Map all state to component props (for redux to connect) const mapStateToProps = state => state; // Map the following action to props const mapDispatchToProps = { setUser: UserAction.setUser, }; // Export a redux connected component export default connect(mapStateToProps, mapDispatchToProps)(App); 3 测试代码 cd /eos-work/frontend npm start 因为这次会读取缓存信息。所以注意先清除下浏览器缓存,或者换一个浏览器。 如果没清除缓存的话,会自动跳到玩家信息页面。 在浏览器中输入网址查看: ![eost09-02.png](https://cdn.steemitimages.com/DQmcXeysPAn5uXnCnXBrK9yXgXswG1Smtnxm9LwxMcYoLWU/eost09-02.png) 输入正确的账号名和私钥后,登录可以看到当前玩家信息。 由于我们还没有比赛,输赢的数据都是零。 ![eost09-03.png](https://cdn.steemitimages.com/DQmfGfJ9Zy6QHT2nY68sGgjUD2mBV7SFRNfksHt4k1Fyy3D/eost09-03.png) 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第三课: https://battles.eos.io/tutorial/lesson3/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg","https://cdn.steemitimages.com/DQmZ3rqhYhhoPkVcdnwWsKSqsZonea3kbRni1U8muCy24so/eost09-01.png","https://cdn.steemitimages.com/DQmcXeysPAn5uXnCnXBrK9yXgXswG1Smtnxm9LwxMcYoLWU/eost09-02.png","https://cdn.steemitimages.com/DQmfGfJ9Zy6QHT2nY68sGgjUD2mBV7SFRNfksHt4k1Fyy3D/eost09-03.png"],"links":["https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-3/frontend/src/components/Game/components/PlayerProfile/images","https://battles.eos.io/tutorial/lesson3/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #28293303/Trx a25f901976aca4a0a0b4440584e97316ad08a7d2
View Raw JSON Data
{
  "trx_id": "a25f901976aca4a0a0b4440584e97316ad08a7d2",
  "block": 28293303,
  "trx_in_block": 22,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-12-05T09:22:27",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "4srm5g-eos",
      "title": "手把手教你玩eos:卡牌游戏第三课——从区块链中读取状态",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第九篇。本篇教程主要学习如何从区块链中获取数据。\n\n0.2 学习内容\n相关准备\n代码编写\n测试代码\n\n0.3 机器环境\ncpu: 1核\n内存: 8G\n操作系统:CentOS 7.4 64位\n服务器所在地:香港\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n1 相关准备\n1.1 课程目标\n为了获取数据,我们使用RPC调用(get_table_rows)传入参数,这将强制它仅返回与包含在多索引表的一行中的当前播放器相关联的数据。然后,我们将在新的个人资料页面中显示前端的数据。\n\n整个流程如下图所示:\n![eost09-01.png](https://cdn.steemitimages.com/DQmZ3rqhYhhoPkVcdnwWsKSqsZonea3kbRni1U8muCy24so/eost09-01.png)\n1.2 准备工作\n进入开发环境容器\n\ndocker exec -it eosdev /bin/bash\n进入前端文件夹\n\ncd /eos-work/frontend/src\n\n2 代码编写\n2.1 编写与区块链通信的代码\n打开负责与后端区块链通信的ApiService.js\n\n\nvi ./services/ApiService.js\n在代码中添加getUserByName()和getCurrentUser()两个函数:\n\t\nclass ApiService {\n\n//===添加getCurrentUser()函数===\nstatic getCurrentUser() {\n    return new Promise((resolve, reject) => {\n      if (!localStorage.getItem(\"cardgame_account\")) {\n        return reject();\n      }\n      takeAction(\"login\", { username: localStorage.getItem(\"cardgame_account\") })\n        .then(() => {\n          resolve(localStorage.getItem(\"cardgame_account\"));\n        })\n        .catch(err => {\n          localStorage.removeItem(\"cardgame_account\");\n          localStorage.removeItem(\"cardgame_key\");\n          reject(err);\n        });\n    });\n  }\n\n//===添加getUserByName()函数===\nstatic async getUserByName(username) {\n    try {\n      const rpc = new Rpc.JsonRpc(process.env.REACT_APP_EOS_HTTP_ENDPOINT);\n      const result = await rpc.get_table_rows({\n        \"json\": true,\n        \"code\": process.env.REACT_APP_EOS_CONTRACT_NAME,    // contract who owns the table\n        \"scope\": process.env.REACT_APP_EOS_CONTRACT_NAME,   // scope of the table\n        \"table\": \"users\",    // name of the table as specified by the contract abi\n        \"limit\": 1,\n        \"lower_bound\": username,\n      });\n      return result.rows[0];\n    } catch (err) {\n      console.error(err);\n    }\n  }\n\n//======\n\n}\n\n2.2 编写显示玩家信息的组件\n我们在Game下面创建PlayerProfile组件负责显示玩家信息\n\n首先,下载图片素材到images文件夹\n\ncd ./components/Game/components/PlayerProfile/\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-3/frontend/src/components/Game/components/PlayerProfile/images\n创建PlayerProfile.jsx\n\nvi PlayerProfile.jsx\n输入代码:\n\nimport React, { Component } from 'react';\nimport { Button } from 'components';\n\nclass PlayerProfile extends Component {\n  render() {\n    // Extract data and event functions from props\n    const { name, winCount, lostCount, onStartGame } = this.props;\n\n    // Display welcome message,\n    //         buttons for login / start game,\n    //         number of winning and losing\n    return (\n      <div className=\"PlayerProfile\">\n        <div className=\"title\">Elemental Battles - powered by EOSIO</div>\n        <div className=\"welcome\">\n          <span>Welcome</span>\n        </div>\n        <div className=\"username\">\n          <span>{ name }</span>\n        </div>\n        <div className=\"record\">\n          <p>Your Current Record</p>\n          <span>Win <span className=\"count\">{ winCount }</span></span>\n          <span> | </span>\n          <span>Lost <span className=\"count\">{ lostCount }</span></span>\n        </div>\n        <div className=\"buttons\">\n          <Button onClick={ onStartGame } className=\"green\">START</Button>\n        </div>\n      </div>\n    )\n  }\n}\n\nexport default PlayerProfile;\n创建index.js\n\nvi index.js\n输入代码:\n\nimport './PlayerProfile.css';\nimport PlayerProfile from './PlayerProfile';\nexport default PlayerProfile;\n\n2.3 添加调用逻辑代码\n回到上级目录,创建组件的index.js\n\ncd ..\nvi index.js\n输入代码:\n\nimport PlayerProfile from './PlayerProfile';\n\nexport {\n  PlayerProfile,\n}\n再回到Game目录下,在Game.jsx中增加代码块\n\ncd ..\nvi Game.jsx\n修改代码如下:\n\n// React core\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Game subcomponents\nimport { PlayerProfile } from './components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services';\n\nclass Game extends Component {\n\n  constructor(props) {\n    // Inherit constructor\n    super(props);\n    // Bind functions\n    this.loadUser = this.loadUser.bind(this);\n    // Call `loadUser` before mounting the app\n    this.loadUser();\n  }\n\n  // Get latest user object from blockchain\n  loadUser() {\n    // Extract `setUser` of `UserAction` and `user.name` of UserReducer from redux\n    const { setUser, user: { name } } = this.props;\n    // Send request the blockchain by calling the ApiService,\n    // Get the user object and store the `win_count`, `lost_count` and `game_data` object\n    return ApiService.getUserByName(name).then(user => {\n      setUser({\n        win_count: user.win_count,\n        lost_count: user.lost_count,\n        game: user.game_data,\n      });\n    });\n  }\n\n  render() {\n    // Extract data from user data of `UserReducer` from redux\n    const { user: { name, win_count, lost_count } } = this.props;\n\n    return (\n      <section className=\"Game\">\n        <PlayerProfile\n          name={ name }\n          winCount={ win_count }\n          lostCount={ lost_count }\n        />\n      </section>\n    )\n  }\n\n}\n\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n\n// Map the following action to props\nconst mapDispatchToProps = {\n  setUser: UserAction.setUser,\n};\n\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(Game);\n再到App文件夹下,修改App.jsx\n\ncd ../App\n\nvi App.jsx\n此次修改如下,注意对比前后差别。\n\n// React core\nimport React, { Component } from 'react';\nimport { connect } from 'react-redux';\n// Components\nimport { Game, Login } from 'components';\n// Services and redux action\nimport { UserAction } from 'actions';\nimport { ApiService } from 'services';\n\nclass App extends Component {\n\n  constructor(props) {\n    // Inherit constructor\n    super(props);\n    // Bind functions\n    this.getCurrentUser = this.getCurrentUser.bind(this);\n    // Call getCurrentUser before mounting the app\n    this.getCurrentUser();\n  }\n\n  getCurrentUser() {\n    // Extract setUser of UserAction from redux\n    const { setUser } = this.props;\n    // Send a request to API (blockchain) to get the current logged in user\n    return ApiService.getCurrentUser()\n      // If the server return a username\n      .then(username => {\n        // Save the username to redux store\n        // For structure, ref: ./frontend/src/reducers/UserReducer.js\n        setUser({ name: username });\n      })\n      // To ignore 401 console error\n      .catch(() => {});\n  }\n\n  render() {\n    // Extract data from state and props (`user` is from redux)\n    const { user: { name } } = this.props;\n\n    // If the username is set in redux, display the Game component\n    // If the username is NOT set in redux, display the Login component\n    return (\n      <div className=\"App\">\n        { name && <Game /> }\n        { !name && <Login /> }\n      </div>\n    );\n  }\n\n}\n\n// Map all state to component props (for redux to connect)\nconst mapStateToProps = state => state;\n\n// Map the following action to props\nconst mapDispatchToProps = {\n  setUser: UserAction.setUser,\n};\n\n// Export a redux connected component\nexport default connect(mapStateToProps, mapDispatchToProps)(App);\n\n3 测试代码\n\ncd /eos-work/frontend\n\nnpm start\n因为这次会读取缓存信息。所以注意先清除下浏览器缓存,或者换一个浏览器。\n如果没清除缓存的话,会自动跳到玩家信息页面。\n\n在浏览器中输入网址查看:\n![eost09-02.png](https://cdn.steemitimages.com/DQmcXeysPAn5uXnCnXBrK9yXgXswG1Smtnxm9LwxMcYoLWU/eost09-02.png)\n输入正确的账号名和私钥后,登录可以看到当前玩家信息。\n由于我们还没有比赛,输赢的数据都是零。\n![eost09-03.png](https://cdn.steemitimages.com/DQmfGfJ9Zy6QHT2nY68sGgjUD2mBV7SFRNfksHt4k1Fyy3D/eost09-03.png)\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n\nEOS官方游戏开发第三课: https://battles.eos.io/tutorial/lesson3/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg\",\"https://cdn.steemitimages.com/DQmZ3rqhYhhoPkVcdnwWsKSqsZonea3kbRni1U8muCy24so/eost09-01.png\",\"https://cdn.steemitimages.com/DQmcXeysPAn5uXnCnXBrK9yXgXswG1Smtnxm9LwxMcYoLWU/eost09-02.png\",\"https://cdn.steemitimages.com/DQmfGfJ9Zy6QHT2nY68sGgjUD2mBV7SFRNfksHt4k1Fyy3D/eost09-03.png\"],\"links\":[\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-3/frontend/src/components/Game/components/PlayerProfile/images\",\"https://battles.eos.io/tutorial/lesson3/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingpublished a new post: 7crwnd-eos
2018/11/28 09:54:51
parent author
parent permlinkeos
authoreoswing
permlink7crwnd-eos
title手把手教你玩eos:卡牌游戏第二课——存储状态和登录
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第八篇。本篇教程主要学习智能合约中如何创建多索引表以及更新表,来完成登录状态的存储。 0.2 学习内容 相关准备 智能合约代码编写 前端代码讲解 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 课程目标 我们首先学习如何在智能合约中存储玩家信息,使用login动作。然后我们将开始构建Web前端,添加Login页面。 为了使Login页面与智能合约交互,我们将使用eosjs来连接到EOSIO区块链。我们使用eosjs库来调用智能合约中的登录操作。接下来,我们将React连接到Redux以存储应用程序状态。最后,我们将所有这些组合在一起并添加一个Game页面,以便我们有一个可用的登录屏幕。 在本课程结束时,玩家应该能够登录游戏并进入游戏中的首屏。 1.2 准备工作 进入开发环境容器 docker exec -it eosdev /bin/bash 进入智能合约文件夹 cd /eos-work/contracts/cardgame 2 智能合约代码编写 2.1 建立存储玩家信息的数据结构 打开cardgame.hpp vi cardgame.hpp 我们要在cardgame.hpp中创建一个user_info来存储以下玩家信息: 玩家的名字 name 胜利计数 win_count 失败计数 lost_count 同时我们还将定义一个login登录动作。 在原有代码基础上输入代码,更新如下: #include <eosiolib/eosio.hpp> using namespace std; class cardgame : public eosio::contract { private: // @abi table users struct user_info { account_name name; uint16_t win_count = 0; uint16_t lost_count = 0; auto primary_key() const { return name; } }; typedef eosio::multi_index<N(users), user_info> users_table; users_table _users; public: cardgame( account_name self ):contract(self),_users(self, self){} void login(account_name username); }; 输入:wq 保存退出 2.2 编写login登录动作逻辑 打开cardgame.cpp vi cardgame.cpp 在这个代码文件里,我们要编写login动作的具体实现。 首先通过require_auth()来检查传入的用户名是否授权有效。 然后检查玩家信息在不在多索引表中。 如果是第一次加入游戏,将在多索引表中为该用户创建一条记录。 在原有代码基础上输入代码,更新如下: #include "gameplay.cpp" void cardgame::login(account_name username) { // Ensure this action is authorized by the player require_auth(username); // Create a record in the table if the player doesn't exist in our app yet auto user_iterator = _users.find(username); if (user_iterator == _users.end()) { user_iterator = _users.emplace(username, [&](auto& new_user) { new_user.name = username; }); } } EOSIO_ABI(cardgame, (login)) 输入:wq 保存退出 2.3 部署智能合约到麒麟测试网 在麒麟网上注册账号 麒麟测试网是对EOS开发者友好的类主网测试环境。 首先我们创建一个账号 在浏览器中输入 http://faucet.cryptokylin.io/create_account?new_account_name new_account_name 就是你要创建的账号名。在这里我使用123123gogogo ![eost08-04.png](https://cdn.steemitimages.com/DQmbgdGemznpjYAqGzk6C3Xdj3M7FNGZFPM5ZZbfN6sh1gg/eost08-04.png) 记下账号的两个公私钥对。 再通过水龙头,给账号领一点测试币。(运行一次发100EOS,24小时内可以运行10次) http://faucet.cryptokylin.io/get_token?your_account_name https://eospark.com/Kylin/account/your_account_name ![eost08-05.png](https://cdn.steemitimages.com/DQmYh6V7BAjPniqBeSFT6tsb26aJfjYLxy8hwrXLXVf4KKK/eost08-05.png) 在EOS区块浏览器中查看下麒麟网的账号 https://eospark.com/Kylin/account/your_account_name ![eost08-06.png](https://cdn.steemitimages.com/DQmZqrsGmEUgaxZUjWDwkGK1EBfwjjtbGxrMRSBKQqZxygj/eost08-06.png) 编译智能合约 编译wast文件 cd /eos-work/contracts/cardgame eosiocpp -o cardgame.wast cardgame.cpp ll 命令行输出如下: ![eost08-07.png](https://cdn.steemitimages.com/DQmRap3C64LTSZYxHw4mWefYh7yExKCzjcLz82VNDq9Fr1N/eost08-07.png) 虽然编译提示使用eosio.cdt工具,但是官方的源文件还是基于传统的eosiocpp。所以还是采用了eosiocpp编译。 编译abi文件 eosiocpp -g cardgame.abi cardgame.cpp 命令行输出如下: ![eost08-08.png](https://cdn.steemitimages.com/DQmU7CfneDbRfr9TKMmXcByY4zvKeVYXtqrRKtPUDE8wkhL/eost08-08.png) 部署智能合约 创建钱包 cleos wallet create -n gamewallet --to-console 命令行输出如下: ![eost08-09.png](https://cdn.steemitimages.com/DQmcCa5seUwbjBNchSfWGGUPtEE7NphbQm3c7hZEcfjwnoz/eost08-09.png) 导入账号私钥 cleos wallet import -n gamewallet 回车后,再输入active权限私钥。 命令行输出如下: ![eost08-10.png](https://cdn.steemitimages.com/DQmZHaPxbEcu2Xsms6RfYyWSzZnbisrpr2JQqQy98Tytnk2/eost08-10.png) 购买点资源 cleos -u https://api-kylin.eosasia.one system delegatebw 123123gogogo 123123gogogo "40.0000 EOS" "40.0000 EOS" 命令行输出如下: ![eost08-11.png](https://cdn.steemitimages.com/DQmaQzGDJAVmCeb29qqvmsR7xzuGsuF74JpJgaHq2QJmHxM/eost08-11.png) cleos -u https://api-kylin.eosasia.one system buyram 123123gogogo 123123gogogo "900 EOS" 命令行输出如下: ![eost08-12.png](https://cdn.steemitimages.com/DQmW5HBZYEWsMQ46j7NMnV9ZnvDH6ipW1NRGyLrJ1PV5kmK/eost08-12.png) 部署智能合约 cleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active 命令行输出如下: ![eost08-13.png](https://cdn.steemitimages.com/DQmTZatdjY7736uHkzYC6x9n8sxGJpckWEvkEvd95wZ2Hqo/eost08-13.png) 在区块浏览器中查看合约 输入网址:https://eospark.com/Kylin/contract/123123gogogo 查看合约情况。 ![eost08-14.png](https://cdn.steemitimages.com/DQmTQtbGAwwNeJwHcPCKVxex6AtHq8qRnDrwCju7Leds1Pe/eost08-14.png) 至此,后端的合约部署完成。 3 前端代码讲解 3.1 相关准备 清理前端文件夹 cd /eos-work rm -rf ./frontend ###下载源文件 apt-get install subversion svn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-2/frontend 安装相关库文件 cd frontend npm update 测试一下 npm start 在浏览器中输入服务器网址查看: ![eost08-01.png](https://cdn.steemitimages.com/DQmYmJYaYavLLtHKEpavEiWDs9nXJ2yHYjkrP7KJbtaGqwL/eost08-01.png) 现在还只能看看,里面还有配置没处理好。 在命令行中输入ctrl+c,退出。 3.2 代码讲解 因为涉及到代码比较多,很多是基础性的react知识。 不做深入拓展理解,跟着教程继续一步步实现也没有问题。 如果读者想知其然后,再知其所以然,可以多谷歌下。 下面主要对主要框架结构和关键代码逻辑进行讲解 代码框架结构 cd src tree -d 可以看到代码结构如下: ![eost08-02.png](https://cdn.steemitimages.com/DQmcvqzrdKH8qycjZTpzceo6wT7EAtEDUPTTyckEqXb3LWp/eost08-02.png) 其中,在components文件夹下,Login和Game分别是登录页面和游戏主页面。 这个运行的流程如下图: ![eost08-03.png](https://cdn.steemitimages.com/DQmcEnEtZP87h8wb5Z9r9JnLCyTbfqykPdUmawnhYWFXz3K/eost08-03.png) 修改配置参数 cd /eos-work/frontend vi .env 修改参数如下: REACT_APP_EOS_CONTRACT_NAME="123123gogogo" REACT_APP_EOS_HTTP_ENDPOINT="https://api-kylin.eosasia.one" :wq保存退出 3.3 运行测试 npm start 在浏览器中输入网址查看。 同时在麒麟网上按照上面的步骤申请一个玩家账号。 我申请了一个cardgametest账号 ![eost08-15.png](https://cdn.steemitimages.com/DQmeBNQVQ7BG7Uhf1DWXdRqtM9hfPpznqTUwnhLFruvDmNh/eost08-15.png) 输入正确的账号名和私钥key后,点击按钮,成功进入游戏主页面,看到welcome! ![eost08-16.png](https://cdn.steemitimages.com/DQmaeNSc8SMD9D1263YwMkBryLPXcpRELwKc69GrTMjHyGW/eost08-16.png) 输入错误的账号名或者key后,点击按钮,进入失败并反馈相关信息。 ![eost08-17.png](https://cdn.steemitimages.com/DQmU2p2Ffum4F8QsB37n6tjFc6ujokSBSji88rzmt575buo/eost08-17.png) 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: EOS官方游戏开发第二课: https://battles.eos.io/tutorial/lesson2/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain","include"],"image":["https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg","https://cdn.steemitimages.com/DQmbgdGemznpjYAqGzk6C3Xdj3M7FNGZFPM5ZZbfN6sh1gg/eost08-04.png","https://cdn.steemitimages.com/DQmYh6V7BAjPniqBeSFT6tsb26aJfjYLxy8hwrXLXVf4KKK/eost08-05.png","https://cdn.steemitimages.com/DQmZqrsGmEUgaxZUjWDwkGK1EBfwjjtbGxrMRSBKQqZxygj/eost08-06.png","https://cdn.steemitimages.com/DQmRap3C64LTSZYxHw4mWefYh7yExKCzjcLz82VNDq9Fr1N/eost08-07.png","https://cdn.steemitimages.com/DQmU7CfneDbRfr9TKMmXcByY4zvKeVYXtqrRKtPUDE8wkhL/eost08-08.png","https://cdn.steemitimages.com/DQmcCa5seUwbjBNchSfWGGUPtEE7NphbQm3c7hZEcfjwnoz/eost08-09.png","https://cdn.steemitimages.com/DQmZHaPxbEcu2Xsms6RfYyWSzZnbisrpr2JQqQy98Tytnk2/eost08-10.png","https://cdn.steemitimages.com/DQmaQzGDJAVmCeb29qqvmsR7xzuGsuF74JpJgaHq2QJmHxM/eost08-11.png","https://cdn.steemitimages.com/DQmW5HBZYEWsMQ46j7NMnV9ZnvDH6ipW1NRGyLrJ1PV5kmK/eost08-12.png","https://cdn.steemitimages.com/DQmTZatdjY7736uHkzYC6x9n8sxGJpckWEvkEvd95wZ2Hqo/eost08-13.png","https://cdn.steemitimages.com/DQmTQtbGAwwNeJwHcPCKVxex6AtHq8qRnDrwCju7Leds1Pe/eost08-14.png","https://cdn.steemitimages.com/DQmYmJYaYavLLtHKEpavEiWDs9nXJ2yHYjkrP7KJbtaGqwL/eost08-01.png","https://cdn.steemitimages.com/DQmcvqzrdKH8qycjZTpzceo6wT7EAtEDUPTTyckEqXb3LWp/eost08-02.png","https://cdn.steemitimages.com/DQmcEnEtZP87h8wb5Z9r9JnLCyTbfqykPdUmawnhYWFXz3K/eost08-03.png","https://cdn.steemitimages.com/DQmeBNQVQ7BG7Uhf1DWXdRqtM9hfPpznqTUwnhLFruvDmNh/eost08-15.png","https://cdn.steemitimages.com/DQmaeNSc8SMD9D1263YwMkBryLPXcpRELwKc69GrTMjHyGW/eost08-16.png","https://cdn.steemitimages.com/DQmU2p2Ffum4F8QsB37n6tjFc6ujokSBSji88rzmt575buo/eost08-17.png"],"links":["http://faucet.cryptokylin.io/create_account?new_account_name","http://faucet.cryptokylin.io/get_token?your_account_name","https://eospark.com/Kylin/account/your_account_name","https://api-kylin.eosasia.one","https://eospark.com/Kylin/contract/123123gogogo","https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-2/frontend","https://battles.eos.io/tutorial/lesson2/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #28092419/Trx 171e28b126813777dbf2d0bc7a3e4e8a873f7da1
View Raw JSON Data
{
  "trx_id": "171e28b126813777dbf2d0bc7a3e4e8a873f7da1",
  "block": 28092419,
  "trx_in_block": 3,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-28T09:54:51",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "7crwnd-eos",
      "title": "手把手教你玩eos:卡牌游戏第二课——存储状态和登录",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![kapai.jpg](https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第八篇。本篇教程主要学习智能合约中如何创建多索引表以及更新表,来完成登录状态的存储。\n\n0.2 学习内容\n相关准备\n智能合约代码编写\n前端代码讲解\n0.3 机器环境\ncpu: 1核\n内存: 8G\n操作系统:CentOS 7.4 64位\n服务器所在地:香港\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n1 相关准备\n1.1 课程目标\n我们首先学习如何在智能合约中存储玩家信息,使用login动作。然后我们将开始构建Web前端,添加Login页面。\n\n为了使Login页面与智能合约交互,我们将使用eosjs来连接到EOSIO区块链。我们使用eosjs库来调用智能合约中的登录操作。接下来,我们将React连接到Redux以存储应用程序状态。最后,我们将所有这些组合在一起并添加一个Game页面,以便我们有一个可用的登录屏幕。\n\n在本课程结束时,玩家应该能够登录游戏并进入游戏中的首屏。\n\n1.2 准备工作\n进入开发环境容器\n\ndocker exec -it eosdev /bin/bash\n进入智能合约文件夹\n\ncd /eos-work/contracts/cardgame\n2 智能合约代码编写\n2.1 建立存储玩家信息的数据结构\n打开cardgame.hpp\n\n\nvi cardgame.hpp\n我们要在cardgame.hpp中创建一个user_info来存储以下玩家信息:\n\n玩家的名字 name\n胜利计数 win_count\n失败计数 lost_count\n同时我们还将定义一个login登录动作。\n\n在原有代码基础上输入代码,更新如下:\n\n#include <eosiolib/eosio.hpp>\n\nusing namespace std;\nclass cardgame : public eosio::contract {\n\n  private:\n\n    // @abi table users\n    struct user_info {\n      account_name    name;\n      uint16_t        win_count = 0;\n      uint16_t        lost_count = 0;\n\n      auto primary_key() const { return name; }\n    };\n\n    typedef eosio::multi_index<N(users), user_info> users_table;\n\n    users_table _users;\n\n  public:\n\n    cardgame( account_name self ):contract(self),_users(self, self){}\n\n    void login(account_name username);\n\n};\n输入:wq 保存退出\n\n2.2 编写login登录动作逻辑\n打开cardgame.cpp\n\n\nvi cardgame.cpp\n在这个代码文件里,我们要编写login动作的具体实现。\n\n首先通过require_auth()来检查传入的用户名是否授权有效。\n然后检查玩家信息在不在多索引表中。\n如果是第一次加入游戏,将在多索引表中为该用户创建一条记录。\n\n在原有代码基础上输入代码,更新如下:\n\n\n#include \"gameplay.cpp\"\n\nvoid cardgame::login(account_name username) {\n  // Ensure this action is authorized by the player\n  require_auth(username);\n\n  // Create a record in the table if the player doesn't exist in our app yet\n  auto user_iterator = _users.find(username);\n  if (user_iterator == _users.end()) {\n    user_iterator = _users.emplace(username,  [&](auto& new_user) {\n      new_user.name = username;\n    });\n  }\n}\n\nEOSIO_ABI(cardgame, (login))\n输入:wq 保存退出\n\n2.3 部署智能合约到麒麟测试网\n在麒麟网上注册账号\n麒麟测试网是对EOS开发者友好的类主网测试环境。\n\n首先我们创建一个账号\n在浏览器中输入\nhttp://faucet.cryptokylin.io/create_account?new_account_name\nnew_account_name 就是你要创建的账号名。在这里我使用123123gogogo\n![eost08-04.png](https://cdn.steemitimages.com/DQmbgdGemznpjYAqGzk6C3Xdj3M7FNGZFPM5ZZbfN6sh1gg/eost08-04.png)\n\n记下账号的两个公私钥对。\n\n再通过水龙头,给账号领一点测试币。(运行一次发100EOS,24小时内可以运行10次)\nhttp://faucet.cryptokylin.io/get_token?your_account_name\nhttps://eospark.com/Kylin/account/your_account_name\n![eost08-05.png](https://cdn.steemitimages.com/DQmYh6V7BAjPniqBeSFT6tsb26aJfjYLxy8hwrXLXVf4KKK/eost08-05.png)\n\n\n在EOS区块浏览器中查看下麒麟网的账号\nhttps://eospark.com/Kylin/account/your_account_name\n![eost08-06.png](https://cdn.steemitimages.com/DQmZqrsGmEUgaxZUjWDwkGK1EBfwjjtbGxrMRSBKQqZxygj/eost08-06.png)\n\n编译智能合约\n编译wast文件\n\ncd /eos-work/contracts/cardgame\n\neosiocpp -o cardgame.wast cardgame.cpp\n\nll\n\n命令行输出如下:\n![eost08-07.png](https://cdn.steemitimages.com/DQmRap3C64LTSZYxHw4mWefYh7yExKCzjcLz82VNDq9Fr1N/eost08-07.png)\n虽然编译提示使用eosio.cdt工具,但是官方的源文件还是基于传统的eosiocpp。所以还是采用了eosiocpp编译。\n\n编译abi文件\n\neosiocpp -g cardgame.abi cardgame.cpp\n\n命令行输出如下:\n![eost08-08.png](https://cdn.steemitimages.com/DQmU7CfneDbRfr9TKMmXcByY4zvKeVYXtqrRKtPUDE8wkhL/eost08-08.png)\n\n\n部署智能合约\n创建钱包\n\ncleos wallet create -n gamewallet --to-console\n\n命令行输出如下:\n![eost08-09.png](https://cdn.steemitimages.com/DQmcCa5seUwbjBNchSfWGGUPtEE7NphbQm3c7hZEcfjwnoz/eost08-09.png)\n\n\n导入账号私钥\n\ncleos wallet import -n gamewallet\n回车后,再输入active权限私钥。\n\n命令行输出如下:\n![eost08-10.png](https://cdn.steemitimages.com/DQmZHaPxbEcu2Xsms6RfYyWSzZnbisrpr2JQqQy98Tytnk2/eost08-10.png)\n\n\n购买点资源\n\ncleos -u https://api-kylin.eosasia.one system delegatebw 123123gogogo 123123gogogo \"40.0000 EOS\" \"40.0000 EOS\"\n\n命令行输出如下:\n![eost08-11.png](https://cdn.steemitimages.com/DQmaQzGDJAVmCeb29qqvmsR7xzuGsuF74JpJgaHq2QJmHxM/eost08-11.png)\n\ncleos -u https://api-kylin.eosasia.one system buyram 123123gogogo 123123gogogo \"900 EOS\"\n\n命令行输出如下:\n![eost08-12.png](https://cdn.steemitimages.com/DQmW5HBZYEWsMQ46j7NMnV9ZnvDH6ipW1NRGyLrJ1PV5kmK/eost08-12.png)\n\n部署智能合约\n\ncleos -u https://api-kylin.eosasia.one set contract 123123gogogo /eos-work/contracts/cardgame -p 123123gogogo@active\n\n命令行输出如下:\n![eost08-13.png](https://cdn.steemitimages.com/DQmTZatdjY7736uHkzYC6x9n8sxGJpckWEvkEvd95wZ2Hqo/eost08-13.png)\n\n在区块浏览器中查看合约\n输入网址:https://eospark.com/Kylin/contract/123123gogogo 查看合约情况。\n![eost08-14.png](https://cdn.steemitimages.com/DQmTQtbGAwwNeJwHcPCKVxex6AtHq8qRnDrwCju7Leds1Pe/eost08-14.png)\n至此,后端的合约部署完成。\n\n3 前端代码讲解\n3.1 相关准备\n清理前端文件夹\n\ncd /eos-work\nrm -rf ./frontend\n###下载源文件\n\napt-get install subversion\n\nsvn checkout https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-2/frontend\n安装相关库文件\n\ncd frontend\nnpm update\n测试一下\n\nnpm start\n在浏览器中输入服务器网址查看:\n![eost08-01.png](https://cdn.steemitimages.com/DQmYmJYaYavLLtHKEpavEiWDs9nXJ2yHYjkrP7KJbtaGqwL/eost08-01.png)\n现在还只能看看,里面还有配置没处理好。\n在命令行中输入ctrl+c,退出。\n\n3.2 代码讲解\n因为涉及到代码比较多,很多是基础性的react知识。\n\n不做深入拓展理解,跟着教程继续一步步实现也没有问题。\n\n如果读者想知其然后,再知其所以然,可以多谷歌下。\n\n下面主要对主要框架结构和关键代码逻辑进行讲解\n\n代码框架结构\n\ncd src\ntree -d\n可以看到代码结构如下:\n![eost08-02.png](https://cdn.steemitimages.com/DQmcvqzrdKH8qycjZTpzceo6wT7EAtEDUPTTyckEqXb3LWp/eost08-02.png)\n其中,在components文件夹下,Login和Game分别是登录页面和游戏主页面。\n\n这个运行的流程如下图:\n![eost08-03.png](https://cdn.steemitimages.com/DQmcEnEtZP87h8wb5Z9r9JnLCyTbfqykPdUmawnhYWFXz3K/eost08-03.png)\n修改配置参数\n\ncd /eos-work/frontend\nvi .env\n修改参数如下:\n\n\nREACT_APP_EOS_CONTRACT_NAME=\"123123gogogo\"\nREACT_APP_EOS_HTTP_ENDPOINT=\"https://api-kylin.eosasia.one\"\n:wq保存退出\n\n3.3 运行测试\n\nnpm start\n在浏览器中输入网址查看。\n同时在麒麟网上按照上面的步骤申请一个玩家账号。\n\n我申请了一个cardgametest账号\n![eost08-15.png](https://cdn.steemitimages.com/DQmeBNQVQ7BG7Uhf1DWXdRqtM9hfPpznqTUwnhLFruvDmNh/eost08-15.png)\n输入正确的账号名和私钥key后,点击按钮,成功进入游戏主页面,看到welcome!\n![eost08-16.png](https://cdn.steemitimages.com/DQmaeNSc8SMD9D1263YwMkBryLPXcpRELwKc69GrTMjHyGW/eost08-16.png)\n输入错误的账号名或者key后,点击按钮,进入失败并反馈相关信息。\n![eost08-17.png](https://cdn.steemitimages.com/DQmU2p2Ffum4F8QsB37n6tjFc6ujokSBSji88rzmt575buo/eost08-17.png)\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n\nEOS官方游戏开发第二课: https://battles.eos.io/tutorial/lesson2/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\",\"include\"],\"image\":[\"https://cdn.steemitimages.com/DQmaJJZq1MgE26X7ok1w8ZeYncFAU4FN2metJeFTjafd8Nk/kapai.jpg\",\"https://cdn.steemitimages.com/DQmbgdGemznpjYAqGzk6C3Xdj3M7FNGZFPM5ZZbfN6sh1gg/eost08-04.png\",\"https://cdn.steemitimages.com/DQmYh6V7BAjPniqBeSFT6tsb26aJfjYLxy8hwrXLXVf4KKK/eost08-05.png\",\"https://cdn.steemitimages.com/DQmZqrsGmEUgaxZUjWDwkGK1EBfwjjtbGxrMRSBKQqZxygj/eost08-06.png\",\"https://cdn.steemitimages.com/DQmRap3C64LTSZYxHw4mWefYh7yExKCzjcLz82VNDq9Fr1N/eost08-07.png\",\"https://cdn.steemitimages.com/DQmU7CfneDbRfr9TKMmXcByY4zvKeVYXtqrRKtPUDE8wkhL/eost08-08.png\",\"https://cdn.steemitimages.com/DQmcCa5seUwbjBNchSfWGGUPtEE7NphbQm3c7hZEcfjwnoz/eost08-09.png\",\"https://cdn.steemitimages.com/DQmZHaPxbEcu2Xsms6RfYyWSzZnbisrpr2JQqQy98Tytnk2/eost08-10.png\",\"https://cdn.steemitimages.com/DQmaQzGDJAVmCeb29qqvmsR7xzuGsuF74JpJgaHq2QJmHxM/eost08-11.png\",\"https://cdn.steemitimages.com/DQmW5HBZYEWsMQ46j7NMnV9ZnvDH6ipW1NRGyLrJ1PV5kmK/eost08-12.png\",\"https://cdn.steemitimages.com/DQmTZatdjY7736uHkzYC6x9n8sxGJpckWEvkEvd95wZ2Hqo/eost08-13.png\",\"https://cdn.steemitimages.com/DQmTQtbGAwwNeJwHcPCKVxex6AtHq8qRnDrwCju7Leds1Pe/eost08-14.png\",\"https://cdn.steemitimages.com/DQmYmJYaYavLLtHKEpavEiWDs9nXJ2yHYjkrP7KJbtaGqwL/eost08-01.png\",\"https://cdn.steemitimages.com/DQmcvqzrdKH8qycjZTpzceo6wT7EAtEDUPTTyckEqXb3LWp/eost08-02.png\",\"https://cdn.steemitimages.com/DQmcEnEtZP87h8wb5Z9r9JnLCyTbfqykPdUmawnhYWFXz3K/eost08-03.png\",\"https://cdn.steemitimages.com/DQmeBNQVQ7BG7Uhf1DWXdRqtM9hfPpznqTUwnhLFruvDmNh/eost08-15.png\",\"https://cdn.steemitimages.com/DQmaeNSc8SMD9D1263YwMkBryLPXcpRELwKc69GrTMjHyGW/eost08-16.png\",\"https://cdn.steemitimages.com/DQmU2p2Ffum4F8QsB37n6tjFc6ujokSBSji88rzmt575buo/eost08-17.png\"],\"links\":[\"http://faucet.cryptokylin.io/create_account?new_account_name\",\"http://faucet.cryptokylin.io/get_token?your_account_name\",\"https://eospark.com/Kylin/account/your_account_name\",\"https://api-kylin.eosasia.one\",\"https://eospark.com/Kylin/contract/123123gogogo\",\"https://github.com/EOSIO/eosio-card-game-repo/branches/lesson-2/frontend\",\"https://battles.eos.io/tutorial/lesson2/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingpublished a new post: 2gojt3-eos
2018/11/21 10:26:15
parent author
parent permlinkeos
authoreoswing
permlink2gojt3-eos
title手把手教你玩eos:卡牌游戏第一课——搭建前后端框架
body@@ -3319,21 +3319,19 @@ %0A & -#60 +lt ;App /& -#62 +gt ;,%0A
json metadata{"tags":["eos","blockchain","include"],"image":["https://cdn.steemitimages.com/DQmemorpDcFFNiJqUZA1Zw9agCQy2HsoA9hRA3qakmfs3DP/1581265020.jpg","https://cdn.steemitimages.com/DQmSVGvK8KBQRZ711tSuAcY39yBbuCWdwB69mKfBLYAmdeh/eost07-00.png","https://cdn.steemitimages.com/DQmeUn2ig24VrFcFcLaXPJ2MHFzm3ZoWVT94pY1sncZumy4/eost07-01.png","https://cdn.steemitimages.com/DQmShnEWqdagUVuQswwDeWTop8RGx7eEasMhVWf8uFbJNZz/eost07-02.png","https://cdn.steemitimages.com/DQmczFaNTJrxd2JNRxrW494rv5Kn5zoU6LZZWfTKH1gRXYn/eost07-03.png","https://cdn.steemitimages.com/DQmbVpNdnutXgBdY6EdbBigvaLSNGFDS83Q5M9G3Uewdi2d/eost07-04.png","https://cdn.steemitimages.com/DQmXWY2x9r5XDs4bNRyyXMBwhB9vtyuM3b58mceWfwyvmB4/eost07-05.png","https://cdn.steemitimages.com/DQmbGaaDbRqQMNLYEeL9JCFzHdZcafjeMNeYcCCufo6hmon/eost07-06.png","https://cdn.steemitimages.com/DQmYNq79pjogYypsUYeAMfzULw17RT1LBHMGg71bt2cjwy2/eost07-07.png","https://cdn.steemitimages.com/DQmdCoh7N9b4L8FJ1vuJeMN9JofReYY9sienRAi6tcNQA5r/eost07-08.png"],"links":["https://battles.eos.io/main","https://deb.nodesource.com/setup_10.x","http://47.75.214.239:3000/,查看:","https://battles.eos.io/tutorial/lesson1/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #27891554/Trx 839c63da3bcea376f5e19fb7911bb3e9831a5133
View Raw JSON Data
{
  "trx_id": "839c63da3bcea376f5e19fb7911bb3e9831a5133",
  "block": 27891554,
  "trx_in_block": 25,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-21T10:26:15",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "2gojt3-eos",
      "title": "手把手教你玩eos:卡牌游戏第一课——搭建前后端框架",
      "body": "@@ -3319,21 +3319,19 @@\n %0A  &\n-#60\n+lt\n ;App /&\n-#62\n+gt\n ;,%0A \n",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\",\"include\"],\"image\":[\"https://cdn.steemitimages.com/DQmemorpDcFFNiJqUZA1Zw9agCQy2HsoA9hRA3qakmfs3DP/1581265020.jpg\",\"https://cdn.steemitimages.com/DQmSVGvK8KBQRZ711tSuAcY39yBbuCWdwB69mKfBLYAmdeh/eost07-00.png\",\"https://cdn.steemitimages.com/DQmeUn2ig24VrFcFcLaXPJ2MHFzm3ZoWVT94pY1sncZumy4/eost07-01.png\",\"https://cdn.steemitimages.com/DQmShnEWqdagUVuQswwDeWTop8RGx7eEasMhVWf8uFbJNZz/eost07-02.png\",\"https://cdn.steemitimages.com/DQmczFaNTJrxd2JNRxrW494rv5Kn5zoU6LZZWfTKH1gRXYn/eost07-03.png\",\"https://cdn.steemitimages.com/DQmbVpNdnutXgBdY6EdbBigvaLSNGFDS83Q5M9G3Uewdi2d/eost07-04.png\",\"https://cdn.steemitimages.com/DQmXWY2x9r5XDs4bNRyyXMBwhB9vtyuM3b58mceWfwyvmB4/eost07-05.png\",\"https://cdn.steemitimages.com/DQmbGaaDbRqQMNLYEeL9JCFzHdZcafjeMNeYcCCufo6hmon/eost07-06.png\",\"https://cdn.steemitimages.com/DQmYNq79pjogYypsUYeAMfzULw17RT1LBHMGg71bt2cjwy2/eost07-07.png\",\"https://cdn.steemitimages.com/DQmdCoh7N9b4L8FJ1vuJeMN9JofReYY9sienRAi6tcNQA5r/eost07-08.png\"],\"links\":[\"https://battles.eos.io/main\",\"https://deb.nodesource.com/setup_10.x\",\"http://47.75.214.239:3000/,查看:\",\"https://battles.eos.io/tutorial/lesson1/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingpublished a new post: 2gojt3-eos
2018/11/21 10:21:12
parent author
parent permlinkeos
authoreoswing
permlink2gojt3-eos
title手把手教你玩eos:卡牌游戏第一课——搭建前后端框架
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![1581265020.jpg](https://cdn.steemitimages.com/DQmemorpDcFFNiJqUZA1Zw9agCQy2HsoA9hRA3qakmfs3DP/1581265020.jpg) 0.引言 0.1教程概况 手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第七篇,从这一篇开始,我们将开始学习如何搭建一个EOS卡牌游戏。本篇教程主要是搭建前后端框架。 0.2 学习内容 1.相关准备 2.构建后端智能合约代码框架 3.构建前端框架 0.3 机器环境 ●cpu: 1核 ●内存: 8G ●操作系统:CentOS 7.4 64位 ●服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1 相关准备 1.1 项目技术栈 此项目来源于eosio官网: https://battles.eos.io/main ![eost07-00.png](https://cdn.steemitimages.com/DQmSVGvK8KBQRZ711tSuAcY39yBbuCWdwB69mKfBLYAmdeh/eost07-00.png) 本项目大体分为智能合约和前端两个部分。 EOSIO智能合约采用C++编写。不过,如我们在第4篇教程介绍智能合约时所说,即使你不会C++也没关系,毕竟入门学习智能合约开发,需要掌握的C++知识并不多。 前端部分,采用React+Redux。 1.2 进入docker容器 下载容器 docker pull eosio/eos-dev:v1.4.1 ![eost07-01.png](https://cdn.steemitimages.com/DQmeUn2ig24VrFcFcLaXPJ2MHFzm3ZoWVT94pY1sncZumy4/eost07-01.png) 建立项目文件夹 mkdir /eosapp mkdir /eosapp/contracts mkdir /eosapp/contracts/cardgame 命令行输出如下: ![eost07-02.png](https://cdn.steemitimages.com/DQmShnEWqdagUVuQswwDeWTop8RGx7eEasMhVWf8uFbJNZz/eost07-02.png) 配置容器 docker run -it -d --net=host --rm --name eosdev -v /eosapp:/eos-work eosio/eos-dev:v1.4.1 /bin/bash 命令行输出如下: ![eost07-03.png](https://cdn.steemitimages.com/DQmczFaNTJrxd2JNRxrW494rv5Kn5zoU6LZZWfTKH1gRXYn/eost07-03.png) 进入docker容器 docker exec -it eosdev /bin/bash 命令行输出如下: ![eost07-04.png](https://cdn.steemitimages.com/DQmbVpNdnutXgBdY6EdbBigvaLSNGFDS83Q5M9G3Uewdi2d/eost07-04.png) 2 构建后端智能合约代码框架 创建智能合约的3个文件 cd /eos-work/contracts/cardgame touch cardgame.hpp touch cardgame.cpp touch gameplay.cpp 命令行输出如下: ![eost07-05.png](https://cdn.steemitimages.com/DQmXWY2x9r5XDs4bNRyyXMBwhB9vtyuM3b58mceWfwyvmB4/eost07-05.png) 三个文件分别为: ●cardgame.hpp - 定义智能合约的C ++头文件。 ●cardgame.cpp - 实现智能合约操作主体文件。 ●gameplay.cpp - 智能合约中使用的内部函数。 编码cardgame.hpp vi cardgame.hpp 输入如下代码: #include <eosiolib/eosio.hpp> using namespace std; class cardgame : public eosio::contract { public: cardgame( account_name self ):contract(self){} }; 输入:wq 保存退出 编码gameplay.cpp vi gameplay.cpp 输入如下代码: #include "cardgame.hpp" 输入:wq 保存退出 编码cardgame.cpp vi cardgame.cpp 输入如下代码: #include "gameplay.cpp" EOSIO_ABI(cardgame, BOOST_PP_SEQ_NIL) 输入:wq 保存退出 3 构建前端框架 安装node 中间遇到[y/n]时,直接输入 y 即可 cd /eos-work curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - apt-get install -y nodejs apt-get install npm npm install n -g n stable npm i -g pm2 构建前端 npm init react-app frontend cd frontend npm start 在浏览器中输入服务器网址,我的是http://47.75.214.239:3000/,查看: ![eost07-06.png](https://cdn.steemitimages.com/DQmbGaaDbRqQMNLYEeL9JCFzHdZcafjeMNeYcCCufo6hmon/eost07-06.png) 修改文件夹代码组织 清空src文件夹中的文件 cd src rm * 添加components文件夹及相关代码 mkdir components mkdir ./components/App vi ./components/App/App.jsx 输入如下代码: import React, { Component } from 'react'; class App extends Component { render() { return ( <div className="App"> EOS Game! </div> ); } } export default App; 输入:wq 保存退出 vi ./components/App/index.js 输入如下代码: import App from './App'; export default App; 输入:wq 保存退出 vi ./components/index.js 输入如下代码: import App from './App'; export { App, } 输入:wq 保存退出 修改src/index.js文件 vi index.js 删除默认代码,输入如下代码: import React from 'react'; import ReactDOM from 'react-dom'; import { App } from './components'; ReactDOM.render( &#60;App /&#62;, document.getElementById('root') ); 输入:wq 保存退出 最终文件夹结构如下: apt-get install tree tree 命令行输出如下: ![eost07-07.png](https://cdn.steemitimages.com/DQmYNq79pjogYypsUYeAMfzULw17RT1LBHMGg71bt2cjwy2/eost07-07.png) 再次运行前端 cd /eos-work/frontend npm start 输入网址查看: ![eost07-08.png](https://cdn.steemitimages.com/DQmdCoh7N9b4L8FJ1vuJeMN9JofReYY9sienRAi6tcNQA5r/eost07-08.png) 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: ●EOS官方游戏开发第一课: https://battles.eos.io/tutorial/lesson1/chapter1 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain","include"],"image":["https://cdn.steemitimages.com/DQmemorpDcFFNiJqUZA1Zw9agCQy2HsoA9hRA3qakmfs3DP/1581265020.jpg","https://cdn.steemitimages.com/DQmSVGvK8KBQRZ711tSuAcY39yBbuCWdwB69mKfBLYAmdeh/eost07-00.png","https://cdn.steemitimages.com/DQmeUn2ig24VrFcFcLaXPJ2MHFzm3ZoWVT94pY1sncZumy4/eost07-01.png","https://cdn.steemitimages.com/DQmShnEWqdagUVuQswwDeWTop8RGx7eEasMhVWf8uFbJNZz/eost07-02.png","https://cdn.steemitimages.com/DQmczFaNTJrxd2JNRxrW494rv5Kn5zoU6LZZWfTKH1gRXYn/eost07-03.png","https://cdn.steemitimages.com/DQmbVpNdnutXgBdY6EdbBigvaLSNGFDS83Q5M9G3Uewdi2d/eost07-04.png","https://cdn.steemitimages.com/DQmXWY2x9r5XDs4bNRyyXMBwhB9vtyuM3b58mceWfwyvmB4/eost07-05.png","https://cdn.steemitimages.com/DQmbGaaDbRqQMNLYEeL9JCFzHdZcafjeMNeYcCCufo6hmon/eost07-06.png","https://cdn.steemitimages.com/DQmYNq79pjogYypsUYeAMfzULw17RT1LBHMGg71bt2cjwy2/eost07-07.png","https://cdn.steemitimages.com/DQmdCoh7N9b4L8FJ1vuJeMN9JofReYY9sienRAi6tcNQA5r/eost07-08.png"],"links":["https://battles.eos.io/main","https://deb.nodesource.com/setup_10.x","http://47.75.214.239:3000/,查看:","https://battles.eos.io/tutorial/lesson1/chapter1"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #27891453/Trx 4eb1b6c492b303b5229d9edfa0f9a4a2164015f6
View Raw JSON Data
{
  "trx_id": "4eb1b6c492b303b5229d9edfa0f9a4a2164015f6",
  "block": 27891453,
  "trx_in_block": 54,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-21T10:21:12",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "2gojt3-eos",
      "title": "手把手教你玩eos:卡牌游戏第一课——搭建前后端框架",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![1581265020.jpg](https://cdn.steemitimages.com/DQmemorpDcFFNiJqUZA1Zw9agCQy2HsoA9hRA3qakmfs3DP/1581265020.jpg)\n0.引言\n0.1教程概况\n手把手教你玩eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n本文是第七篇,从这一篇开始,我们将开始学习如何搭建一个EOS卡牌游戏。本篇教程主要是搭建前后端框架。\n\n0.2 学习内容\n1.相关准备\n2.构建后端智能合约代码框架\n3.构建前端框架\n\n0.3 机器环境\n●cpu: 1核\n●内存: 8G\n●操作系统:CentOS 7.4 64位\n●服务器所在地:香港\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n1 相关准备\n1.1 项目技术栈\n此项目来源于eosio官网:\nhttps://battles.eos.io/main\n![eost07-00.png](https://cdn.steemitimages.com/DQmSVGvK8KBQRZ711tSuAcY39yBbuCWdwB69mKfBLYAmdeh/eost07-00.png)\n\n本项目大体分为智能合约和前端两个部分。\nEOSIO智能合约采用C++编写。不过,如我们在第4篇教程介绍智能合约时所说,即使你不会C++也没关系,毕竟入门学习智能合约开发,需要掌握的C++知识并不多。\n前端部分,采用React+Redux。\n\n1.2 进入docker容器\n下载容器\n\ndocker pull eosio/eos-dev:v1.4.1\n![eost07-01.png](https://cdn.steemitimages.com/DQmeUn2ig24VrFcFcLaXPJ2MHFzm3ZoWVT94pY1sncZumy4/eost07-01.png)\n\n建立项目文件夹\n\nmkdir /eosapp\nmkdir /eosapp/contracts\nmkdir /eosapp/contracts/cardgame\n\n命令行输出如下:\n![eost07-02.png](https://cdn.steemitimages.com/DQmShnEWqdagUVuQswwDeWTop8RGx7eEasMhVWf8uFbJNZz/eost07-02.png)\n\n配置容器\n\ndocker run -it -d --net=host --rm --name eosdev -v /eosapp:/eos-work eosio/eos-dev:v1.4.1 /bin/bash\n\n命令行输出如下:\n![eost07-03.png](https://cdn.steemitimages.com/DQmczFaNTJrxd2JNRxrW494rv5Kn5zoU6LZZWfTKH1gRXYn/eost07-03.png)\n\n进入docker容器\n\ndocker exec -it eosdev /bin/bash\n\n命令行输出如下:\n![eost07-04.png](https://cdn.steemitimages.com/DQmbVpNdnutXgBdY6EdbBigvaLSNGFDS83Q5M9G3Uewdi2d/eost07-04.png)\n\n2 构建后端智能合约代码框架\n创建智能合约的3个文件\n\ncd /eos-work/contracts/cardgame\n\ntouch cardgame.hpp\ntouch cardgame.cpp\ntouch gameplay.cpp\n\n命令行输出如下:\n![eost07-05.png](https://cdn.steemitimages.com/DQmXWY2x9r5XDs4bNRyyXMBwhB9vtyuM3b58mceWfwyvmB4/eost07-05.png)\n\n三个文件分别为:\n●cardgame.hpp - 定义智能合约的C ++头文件。\n●cardgame.cpp - 实现智能合约操作主体文件。\n●gameplay.cpp - 智能合约中使用的内部函数。\n\n编码cardgame.hpp\n\nvi cardgame.hpp\n输入如下代码:\n\n#include <eosiolib/eosio.hpp>\n\nusing namespace std;\nclass cardgame : public eosio::contract {\n\n  public:\n\n    cardgame( account_name self ):contract(self){}\n\n};\n输入:wq 保存退出\n\n编码gameplay.cpp\n\nvi gameplay.cpp\n输入如下代码:\n\n#include \"cardgame.hpp\"\n输入:wq 保存退出\n\n编码cardgame.cpp\n\nvi cardgame.cpp\n输入如下代码:\n\n\n#include \"gameplay.cpp\"\n\nEOSIO_ABI(cardgame, BOOST_PP_SEQ_NIL)\n输入:wq 保存退出\n\n3 构建前端框架\n安装node\n中间遇到[y/n]时,直接输入 y 即可\n\ncd /eos-work\ncurl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -\napt-get install -y nodejs\napt-get install npm\nnpm install n -g\nn stable\nnpm i -g pm2\n构建前端\n\nnpm init react-app frontend\ncd frontend\nnpm start\n在浏览器中输入服务器网址,我的是http://47.75.214.239:3000/,查看:\n![eost07-06.png](https://cdn.steemitimages.com/DQmbGaaDbRqQMNLYEeL9JCFzHdZcafjeMNeYcCCufo6hmon/eost07-06.png)\n\n修改文件夹代码组织\n清空src文件夹中的文件\n\ncd src\nrm *\n\n添加components文件夹及相关代码\n\nmkdir components\nmkdir ./components/App\n\nvi ./components/App/App.jsx\n输入如下代码:\n\nimport React, { Component } from 'react';\n\nclass App extends Component {\n\n  render() {\n    return (\n      <div className=\"App\">\n\tEOS Game!\n      </div>\n    );\n  }\n\n}\n\nexport default App;\n输入:wq 保存退出\n\nvi ./components/App/index.js\n输入如下代码:\n\nimport App from './App';\n\nexport default App;\n输入:wq 保存退出\n\nvi ./components/index.js\n输入如下代码:\n\nimport App from './App';\n\nexport {\n  App,\n}\n输入:wq 保存退出\n\n修改src/index.js文件\n\nvi index.js\n删除默认代码,输入如下代码:\n\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { App } from './components';\n\nReactDOM.render(\n  &#60;App /&#62;,\n  document.getElementById('root')\n);\n输入:wq 保存退出\n\n最终文件夹结构如下:\n\napt-get install tree\ntree\n\n命令行输出如下:\n![eost07-07.png](https://cdn.steemitimages.com/DQmYNq79pjogYypsUYeAMfzULw17RT1LBHMGg71bt2cjwy2/eost07-07.png)\n\n再次运行前端\n\ncd /eos-work/frontend\nnpm start\n输入网址查看:\n![eost07-08.png](https://cdn.steemitimages.com/DQmdCoh7N9b4L8FJ1vuJeMN9JofReYY9sienRAi6tcNQA5r/eost07-08.png)\n\n4 后记\n延伸阅读\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n●EOS官方游戏开发第一课: https://battles.eos.io/tutorial/lesson1/chapter1\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\",\"include\"],\"image\":[\"https://cdn.steemitimages.com/DQmemorpDcFFNiJqUZA1Zw9agCQy2HsoA9hRA3qakmfs3DP/1581265020.jpg\",\"https://cdn.steemitimages.com/DQmSVGvK8KBQRZ711tSuAcY39yBbuCWdwB69mKfBLYAmdeh/eost07-00.png\",\"https://cdn.steemitimages.com/DQmeUn2ig24VrFcFcLaXPJ2MHFzm3ZoWVT94pY1sncZumy4/eost07-01.png\",\"https://cdn.steemitimages.com/DQmShnEWqdagUVuQswwDeWTop8RGx7eEasMhVWf8uFbJNZz/eost07-02.png\",\"https://cdn.steemitimages.com/DQmczFaNTJrxd2JNRxrW494rv5Kn5zoU6LZZWfTKH1gRXYn/eost07-03.png\",\"https://cdn.steemitimages.com/DQmbVpNdnutXgBdY6EdbBigvaLSNGFDS83Q5M9G3Uewdi2d/eost07-04.png\",\"https://cdn.steemitimages.com/DQmXWY2x9r5XDs4bNRyyXMBwhB9vtyuM3b58mceWfwyvmB4/eost07-05.png\",\"https://cdn.steemitimages.com/DQmbGaaDbRqQMNLYEeL9JCFzHdZcafjeMNeYcCCufo6hmon/eost07-06.png\",\"https://cdn.steemitimages.com/DQmYNq79pjogYypsUYeAMfzULw17RT1LBHMGg71bt2cjwy2/eost07-07.png\",\"https://cdn.steemitimages.com/DQmdCoh7N9b4L8FJ1vuJeMN9JofReYY9sienRAi6tcNQA5r/eost07-08.png\"],\"links\":[\"https://battles.eos.io/main\",\"https://deb.nodesource.com/setup_10.x\",\"http://47.75.214.239:3000/,查看:\",\"https://battles.eos.io/tutorial/lesson1/chapter1\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingpublished a new post: eos-eos
2018/11/14 07:52:24
parent author
parent permlinkeos
authoreoswing
permlinkeos-eos
title手把手教你玩eos:架设EOS区块浏览器
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![999.jpg](https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg) 0.引言 0.1教程概况 手把手教你学eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第六篇,主要是讲解如何搭建一个EOS区块浏览器。 0.2 学习内容 1.相关准备知识 2.配置docker容器环境 3.架设区块浏览器 0.3 机器环境 cpu: 1核 内存: 8G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 1. 相关准备知识 1.1 硬件说明 本教程仅仅是演示如何一步步搭建一个区块浏览器,所以硬件配置相对较低。如果有持续运行区块浏览器的需求,请相应调高硬件配置。 1.2 架设目标 架设的目标演示网站为: https://eosnetworkmonitor.io/ ![eost06-00.png](https://cdn.steemitimages.com/DQmNxE5UPqRKCU9K5sibwUzR8ygrnoWC3cuNf7yutX94waV/eost06-00.png) 对应的github源码地址为: https://github.com/CryptoLions/EOS-Network-monitor 2. 配置docker容器环境 2.1 配置ubuntu容器 下载镜像 docker pull ubuntu:18.04 命令行输出如下: ![eost06-01.png](https://cdn.steemitimages.com/DQmQ7P4HewsX8bNvh5qCvriDskDHRxuneiFxFVn3wZDHudC/eost06-01.png) 配置容器 docker run -it -d --net=host --rm --name eosmonitor -v /data/monitor:/monitor-work ubuntu:18.04 /bin/bash 命令行输出如下: ![eost06-02.png](https://cdn.steemitimages.com/DQmacbJ2V2JHSMY23AVcFMzugfFwJJ8aX3iSiJxmqCAd4VC/eost06-02.png) 进入docker容器 docker exec -it eosmonitor /bin/bash 更新源索引 apt-get update 命令行输出如下: ![eost06-03.png](https://cdn.steemitimages.com/DQmNQP5tywLpLtAzDe8f13uJAYLb3FFTH5G55rbdzYL5awf/eost06-03.png) 安装相关组件 中间遇到[y/n]时,直接输入 y 即可 apt-get install sudo apt-get install curl apt-get install git apt-get install vim 2.2 配置环境 安装Nodejs v10和mongodb curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - sudo apt-get install -y nodejs sudo apt-get install npm sudo npm install n -g sudo n stable npm i -g pm2 sudo apt-get install mongodb 查看nodejs和mongodb安装版本 mongo --version node --version 命令行输出如下: ![eost06-04.png](https://cdn.steemitimages.com/DQmTzQvZy9dK53zfcqjRP5RJxwvDPg1o2iVCjZAAqNZvwWa/eost06-04.png) 创建数据和日志文件目录 mkdir /monitor-work/mongo mkdir /monitor-work/mongo/data mkdir /monitor-work/mongo/logs 运行mongo服务 mongod --dbpath=/monitor-work/mongo/data --fork --port 27017 --bind_ip localhost --logpath=/monitor-work/mongo/logs/work.log --logappend 命令行输出如下: ![eost06-05.png](https://cdn.steemitimages.com/DQmfJvaRpCnhs4iRVwWQnnegc67aVUHSiD8WErfJX5aiq9u/eost06-05.png) 3. 架设区块浏览器 3.1 配置后端 git下载源码 cd /monitor-work git clone https://github.com/CryptoLions/EOS-Network-monitor.git 命令行输出如下: ![eost06-06.png](https://cdn.steemitimages.com/DQmPt9At8S1kogExRWVtdrUX7xqvM9UL7UnT1S3pGcj2pdA/eost06-06.png) 修改配置文件 cd /monitor-work/EOS-Network-monitor/netmon-backend/config/ cp default.json default.json.back vi default.json 这里目前有三个地方需要注意,分别用箭头标识出来了: 1.是你的服务器后台网址,这里我输入的是自己的服务器ip地址 2.可用的eosapi服务节点网址 3.是备用的eosapi服务节点网址 ![eost06-07.png](https://cdn.steemitimages.com/DQmNYtX9axqvxSJn3zAKQhmQmLtK2oDiwC4puYZYRkcD1BN/eost06-07.png) 这个配置文件里还有很多区块浏览器运营需要的账号配置,在这里就不一一配置了。感兴趣的可以看源码注释。 启动后端 cd .. npm install pm2 start ecosystem.config.js 3.2 配置前端 安装yarn curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt-get update && sudo apt-get install yarn yarn --version 修改配置文件 vi /monitor-work/EOS-Network-monitor/netmon-frontend/app/constants.js 这里主要是修改成你服务器的网址。 我这里修改为 http://47.75.214.239:3002 ![eost06-08.png](https://cdn.steemitimages.com/DQmRY7gnB8xqqTStnJUFowW8ZpmCQ1Xnm4hwjXYrb6E3sex/eost06-08.png) 启动前端 其中 yarn build 为可选,在运营环境时使用。 cd /monitor-work/EOS-Network-monitor/netmon-frontend/ yarn yarn build yarn start 最后在浏览器中输入网址查看 ![eost06-09.png](https://cdn.steemitimages.com/DQmRddsdjP12Ag9ZoKTaR2EJstB9j8yqhREntB5eZb1p3s9/eost06-09.png) 其中,因为后端mongo数据库在同步区块中。注意看以下面板: ![eost06-10.png](https://cdn.steemitimages.com/DQmeNRXVh2CTHyjQkCGDrqZguTbapdrgd9mh8cdNDgbrpVZ/eost06-10.png) 可以与http://eosnetworkmonitor.io 官方演示的对照。 只有当区块数据同步到最新高度附近,区块数据的显示和查询才是完备的。 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg","https://cdn.steemitimages.com/DQmNxE5UPqRKCU9K5sibwUzR8ygrnoWC3cuNf7yutX94waV/eost06-00.png","https://cdn.steemitimages.com/DQmQ7P4HewsX8bNvh5qCvriDskDHRxuneiFxFVn3wZDHudC/eost06-01.png","https://cdn.steemitimages.com/DQmacbJ2V2JHSMY23AVcFMzugfFwJJ8aX3iSiJxmqCAd4VC/eost06-02.png","https://cdn.steemitimages.com/DQmNQP5tywLpLtAzDe8f13uJAYLb3FFTH5G55rbdzYL5awf/eost06-03.png","https://cdn.steemitimages.com/DQmTzQvZy9dK53zfcqjRP5RJxwvDPg1o2iVCjZAAqNZvwWa/eost06-04.png","https://cdn.steemitimages.com/DQmfJvaRpCnhs4iRVwWQnnegc67aVUHSiD8WErfJX5aiq9u/eost06-05.png","https://cdn.steemitimages.com/DQmPt9At8S1kogExRWVtdrUX7xqvM9UL7UnT1S3pGcj2pdA/eost06-06.png","https://cdn.steemitimages.com/DQmNYtX9axqvxSJn3zAKQhmQmLtK2oDiwC4puYZYRkcD1BN/eost06-07.png","https://cdn.steemitimages.com/DQmRY7gnB8xqqTStnJUFowW8ZpmCQ1Xnm4hwjXYrb6E3sex/eost06-08.png","https://cdn.steemitimages.com/DQmRddsdjP12Ag9ZoKTaR2EJstB9j8yqhREntB5eZb1p3s9/eost06-09.png","https://cdn.steemitimages.com/DQmeNRXVh2CTHyjQkCGDrqZguTbapdrgd9mh8cdNDgbrpVZ/eost06-10.png"],"links":["https://eosnetworkmonitor.io/","https://github.com/CryptoLions/EOS-Network-monitor","https://deb.nodesource.com/setup_10.x","https://github.com/CryptoLions/EOS-Network-monitor.git","https://dl.yarnpkg.com/debian/pubkey.gpg","https://dl.yarnpkg.com/debian/","http://47.75.214.239:3002","http://eosnetworkmonitor.io"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #27686997/Trx 6cf3ba342dd015eb892bcda585d7cea673884216
View Raw JSON Data
{
  "trx_id": "6cf3ba342dd015eb892bcda585d7cea673884216",
  "block": 27686997,
  "trx_in_block": 31,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-14T07:52:24",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-eos",
      "title": "手把手教你玩eos:架设EOS区块浏览器",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n\n![999.jpg](https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg)\n\n0.引言\n\n0.1教程概况\n\n手把手教你学eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n\n本文是第六篇,主要是讲解如何搭建一个EOS区块浏览器。\n\n\n\n0.2 学习内容\n\n1.相关准备知识\n\n2.配置docker容器环境\n\n3.架设区块浏览器\n\n\n\n0.3 机器环境\n\ncpu: 1核\n\n内存: 8G\n\n操作系统:CentOS 7.4 64位\n\n服务器所在地:香港\n\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n\n\n1. 相关准备知识\n\n1.1 硬件说明\n\n本教程仅仅是演示如何一步步搭建一个区块浏览器,所以硬件配置相对较低。如果有持续运行区块浏览器的需求,请相应调高硬件配置。\n\n\n\n1.2 架设目标\n\n架设的目标演示网站为: https://eosnetworkmonitor.io/\n![eost06-00.png](https://cdn.steemitimages.com/DQmNxE5UPqRKCU9K5sibwUzR8ygrnoWC3cuNf7yutX94waV/eost06-00.png)\n\n\n对应的github源码地址为: https://github.com/CryptoLions/EOS-Network-monitor\n\n\n\n2. 配置docker容器环境\n\n2.1 配置ubuntu容器\n\n下载镜像\n\ndocker pull ubuntu:18.04\n\n\n\n命令行输出如下:\n![eost06-01.png](https://cdn.steemitimages.com/DQmQ7P4HewsX8bNvh5qCvriDskDHRxuneiFxFVn3wZDHudC/eost06-01.png)\n\n\n\n\n配置容器\n\ndocker run -it -d --net=host --rm --name eosmonitor -v /data/monitor:/monitor-work ubuntu:18.04 /bin/bash\n\n\n\n命令行输出如下:\n![eost06-02.png](https://cdn.steemitimages.com/DQmacbJ2V2JHSMY23AVcFMzugfFwJJ8aX3iSiJxmqCAd4VC/eost06-02.png)\n\n\n\n\n进入docker容器\n\ndocker exec -it eosmonitor /bin/bash\n\n\n\n更新源索引\n\napt-get update\n\n\n\n命令行输出如下:\n![eost06-03.png](https://cdn.steemitimages.com/DQmNQP5tywLpLtAzDe8f13uJAYLb3FFTH5G55rbdzYL5awf/eost06-03.png)\n\n\n\n\n安装相关组件\n\n中间遇到[y/n]时,直接输入 y 即可\n\napt-get install sudo\n\napt-get install curl\n\napt-get install git\n\napt-get install vim\n\n\n\n2.2 配置环境\n\n安装Nodejs v10和mongodb\n\ncurl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -\n\nsudo apt-get install -y nodejs\n\nsudo apt-get install npm\n\nsudo npm install n -g\n\nsudo n stable\n\nnpm i -g pm2\n\nsudo apt-get install mongodb\n\n\n\n查看nodejs和mongodb安装版本\n\nmongo --version\n\nnode --version\n\n\n\n命令行输出如下:\n![eost06-04.png](https://cdn.steemitimages.com/DQmTzQvZy9dK53zfcqjRP5RJxwvDPg1o2iVCjZAAqNZvwWa/eost06-04.png)\n\n\n\n\n创建数据和日志文件目录\n\nmkdir /monitor-work/mongo\n\nmkdir /monitor-work/mongo/data\n\nmkdir /monitor-work/mongo/logs\n\n\n\n运行mongo服务\n\nmongod --dbpath=/monitor-work/mongo/data --fork --port 27017 --bind_ip localhost --logpath=/monitor-work/mongo/logs/work.log --logappend\n\n\n\n命令行输出如下:\n\n![eost06-05.png](https://cdn.steemitimages.com/DQmfJvaRpCnhs4iRVwWQnnegc67aVUHSiD8WErfJX5aiq9u/eost06-05.png)\n\n\n\n3. 架设区块浏览器\n\n3.1 配置后端\n\ngit下载源码\n\ncd /monitor-work\n\ngit clone https://github.com/CryptoLions/EOS-Network-monitor.git\n\n\n\n命令行输出如下:\n\n![eost06-06.png](https://cdn.steemitimages.com/DQmPt9At8S1kogExRWVtdrUX7xqvM9UL7UnT1S3pGcj2pdA/eost06-06.png)\n\n\n\n修改配置文件\n\ncd /monitor-work/EOS-Network-monitor/netmon-backend/config/\n\ncp default.json default.json.back\n\nvi default.json\n\n这里目前有三个地方需要注意,分别用箭头标识出来了:\n\n1.是你的服务器后台网址,这里我输入的是自己的服务器ip地址\n\n2.可用的eosapi服务节点网址\n\n3.是备用的eosapi服务节点网址\n![eost06-07.png](https://cdn.steemitimages.com/DQmNYtX9axqvxSJn3zAKQhmQmLtK2oDiwC4puYZYRkcD1BN/eost06-07.png)\n\n\n这个配置文件里还有很多区块浏览器运营需要的账号配置,在这里就不一一配置了。感兴趣的可以看源码注释。\n\n\n\n启动后端\n\ncd ..\n\nnpm install\n\npm2 start ecosystem.config.js\n\n\n\n3.2 配置前端\n\n安装yarn\n\ncurl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -\n\necho \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list\n\nsudo apt-get update && sudo apt-get install yarn\n\n\n\nyarn --version\n\n\n\n修改配置文件\n\nvi /monitor-work/EOS-Network-monitor/netmon-frontend/app/constants.js\n\n这里主要是修改成你服务器的网址。\n\n我这里修改为 http://47.75.214.239:3002\n![eost06-08.png](https://cdn.steemitimages.com/DQmRY7gnB8xqqTStnJUFowW8ZpmCQ1Xnm4hwjXYrb6E3sex/eost06-08.png)\n\n\n\n\n启动前端\n\n其中 yarn build 为可选,在运营环境时使用。\n\ncd /monitor-work/EOS-Network-monitor/netmon-frontend/\n\nyarn\n\n\n\nyarn build\n\n\n\nyarn start\n\n\n\n最后在浏览器中输入网址查看\n![eost06-09.png](https://cdn.steemitimages.com/DQmRddsdjP12Ag9ZoKTaR2EJstB9j8yqhREntB5eZb1p3s9/eost06-09.png)\n\n\n其中,因为后端mongo数据库在同步区块中。注意看以下面板:\n![eost06-10.png](https://cdn.steemitimages.com/DQmeNRXVh2CTHyjQkCGDrqZguTbapdrgd9mh8cdNDgbrpVZ/eost06-10.png)\n\n\n可以与http://eosnetworkmonitor.io 官方演示的对照。\n\n\n\n只有当区块数据同步到最新高度附近,区块数据的显示和查询才是完备的。\n\n\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg\",\"https://cdn.steemitimages.com/DQmNxE5UPqRKCU9K5sibwUzR8ygrnoWC3cuNf7yutX94waV/eost06-00.png\",\"https://cdn.steemitimages.com/DQmQ7P4HewsX8bNvh5qCvriDskDHRxuneiFxFVn3wZDHudC/eost06-01.png\",\"https://cdn.steemitimages.com/DQmacbJ2V2JHSMY23AVcFMzugfFwJJ8aX3iSiJxmqCAd4VC/eost06-02.png\",\"https://cdn.steemitimages.com/DQmNQP5tywLpLtAzDe8f13uJAYLb3FFTH5G55rbdzYL5awf/eost06-03.png\",\"https://cdn.steemitimages.com/DQmTzQvZy9dK53zfcqjRP5RJxwvDPg1o2iVCjZAAqNZvwWa/eost06-04.png\",\"https://cdn.steemitimages.com/DQmfJvaRpCnhs4iRVwWQnnegc67aVUHSiD8WErfJX5aiq9u/eost06-05.png\",\"https://cdn.steemitimages.com/DQmPt9At8S1kogExRWVtdrUX7xqvM9UL7UnT1S3pGcj2pdA/eost06-06.png\",\"https://cdn.steemitimages.com/DQmNYtX9axqvxSJn3zAKQhmQmLtK2oDiwC4puYZYRkcD1BN/eost06-07.png\",\"https://cdn.steemitimages.com/DQmRY7gnB8xqqTStnJUFowW8ZpmCQ1Xnm4hwjXYrb6E3sex/eost06-08.png\",\"https://cdn.steemitimages.com/DQmRddsdjP12Ag9ZoKTaR2EJstB9j8yqhREntB5eZb1p3s9/eost06-09.png\",\"https://cdn.steemitimages.com/DQmeNRXVh2CTHyjQkCGDrqZguTbapdrgd9mh8cdNDgbrpVZ/eost06-10.png\"],\"links\":[\"https://eosnetworkmonitor.io/\",\"https://github.com/CryptoLions/EOS-Network-monitor\",\"https://deb.nodesource.com/setup_10.x\",\"https://github.com/CryptoLions/EOS-Network-monitor.git\",\"https://dl.yarnpkg.com/debian/pubkey.gpg\",\"https://dl.yarnpkg.com/debian/\",\"http://47.75.214.239:3002\",\"http://eosnetworkmonitor.io\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2018/11/07 09:10:51
votereoswing
authoreoswing
permlinkstatement-of-ownership
weight10000 (100.00%)
Transaction InfoBlock #27487089/Trx 533fd99154e5d524710b1309558cc4562d4b4d1b
View Raw JSON Data
{
  "trx_id": "533fd99154e5d524710b1309558cc4562d4b4d1b",
  "block": 27487089,
  "trx_in_block": 3,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:51",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "statement-of-ownership",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / eos
2018/11/07 09:10:48
votereoswing
authoreoswing
permlinkeos
weight10000 (100.00%)
Transaction InfoBlock #27487088/Trx 26c80c5638c8178a6bf7f15d76e65f79382095b5
View Raw JSON Data
{
  "trx_id": "26c80c5638c8178a6bf7f15d76e65f79382095b5",
  "block": 27487088,
  "trx_in_block": 9,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:48",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / eos-docker-eos
2018/11/07 09:10:45
votereoswing
authoreoswing
permlinkeos-docker-eos
weight10000 (100.00%)
Transaction InfoBlock #27487087/Trx 751227d2c831e692412bd4afa2fe977db0e6c069
View Raw JSON Data
{
  "trx_id": "751227d2c831e692412bd4afa2fe977db0e6c069",
  "block": 27487087,
  "trx_in_block": 37,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:45",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "eos-docker-eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 5m7etd-eos
2018/11/07 09:10:42
votereoswing
authoreoswing
permlink5m7etd-eos
weight10000 (100.00%)
Transaction InfoBlock #27487086/Trx db8c178c70e95387e6b65ea2e2c7095de3463e48
View Raw JSON Data
{
  "trx_id": "db8c178c70e95387e6b65ea2e2c7095de3463e48",
  "block": 27487086,
  "trx_in_block": 17,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:42",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "5m7etd-eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / eos-helloeos
2018/11/07 09:10:39
votereoswing
authoreoswing
permlinkeos-helloeos
weight10000 (100.00%)
Transaction InfoBlock #27487085/Trx ab1a1809d545213009c5ad33ac6ad817586964e5
View Raw JSON Data
{
  "trx_id": "ab1a1809d545213009c5ad33ac6ad817586964e5",
  "block": 27487085,
  "trx_in_block": 36,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:39",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "eos-helloeos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 5e4rap-eos
2018/11/07 09:10:39
votereoswing
authoreoswing
permlink5e4rap-eos
weight10000 (100.00%)
Transaction InfoBlock #27487085/Trx b218f95733e095cf364f674d0bdfc64b86a9deba
View Raw JSON Data
{
  "trx_id": "b218f95733e095cf364f674d0bdfc64b86a9deba",
  "block": 27487085,
  "trx_in_block": 20,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:39",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "5e4rap-eos",
      "weight": 10000
    }
  ]
}
eoswingupvoted (100.00%) @eoswing / 5pv9a2-eos
2018/11/07 09:10:30
votereoswing
authoreoswing
permlink5pv9a2-eos
weight10000 (100.00%)
Transaction InfoBlock #27487082/Trx 1606a9aa75b5737d08f3c03eabeb1a1827c4719e
View Raw JSON Data
{
  "trx_id": "1606a9aa75b5737d08f3c03eabeb1a1827c4719e",
  "block": 27487082,
  "trx_in_block": 27,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:10:30",
  "op": [
    "vote",
    {
      "voter": "eoswing",
      "author": "eoswing",
      "permlink": "5pv9a2-eos",
      "weight": 10000
    }
  ]
}
2018/11/07 09:09:00
parent authoreoswing
parent permlink5e4rap-eos
authorcheetah
permlinkcheetah-re-eoswing5e4rap-eos
title
bodyHi! I am a robot. I just upvoted you! I found similar content that readers might be interested in: https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.cpp
json metadata
Transaction InfoBlock #27487052/Trx 14f31b230b3e616456a43ec1b67e73780320e966
View Raw JSON Data
{
  "trx_id": "14f31b230b3e616456a43ec1b67e73780320e966",
  "block": 27487052,
  "trx_in_block": 20,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:09:00",
  "op": [
    "comment",
    {
      "parent_author": "eoswing",
      "parent_permlink": "5e4rap-eos",
      "author": "cheetah",
      "permlink": "cheetah-re-eoswing5e4rap-eos",
      "title": "",
      "body": "Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:\nhttps://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.cpp",
      "json_metadata": ""
    }
  ]
}
cheetahupvoted (0.08%) @eoswing / 5e4rap-eos
2018/11/07 09:08:57
votercheetah
authoreoswing
permlink5e4rap-eos
weight8 (0.08%)
Transaction InfoBlock #27487051/Trx 97bdf15daf27e6976ee73b458f3ee2dced672fb1
View Raw JSON Data
{
  "trx_id": "97bdf15daf27e6976ee73b458f3ee2dced672fb1",
  "block": 27487051,
  "trx_in_block": 10,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:08:57",
  "op": [
    "vote",
    {
      "voter": "cheetah",
      "author": "eoswing",
      "permlink": "5e4rap-eos",
      "weight": 8
    }
  ]
}
eoswingpublished a new post: 5e4rap-eos
2018/11/07 09:08:45
parent author
parent permlinkeos
authoreoswing
permlink5e4rap-eos
title手把手教你玩eos:编写智能合约游戏——三连棋
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 ![999.jpg](https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg) 0. 引言 0.1 教程概况 手把手教你学eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第五篇,主要是如何使用eos智能合约编写一个游戏:三连棋。 0.2 学习内容 1.相关准备知识 2.编写智能合约 3.编译和运行智能合约 0.3 机器环境 cpu: 1核 内存: 2G 操作系统:CentOS 7.4 64位 服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 提示:以下命令行默认在root权限下执行。如遇权限问题,请在命令前加sudo。 1. 相关准备知识 1.1 三连棋游戏规则 三连棋,又称“井字棋”,是棋类的一种,棋盘为九宫格,呈“井”字形,玩家双方各代表○或×,在棋盘上任意一方连成三个(横竖斜均可)就胜利了。 ![eost05-01.jpg](https://cdn.steemitimages.com/DQmdussHfbdCMBxDqXseyFeUqEFXS7PeBHkBpDA4wVoKjry/eost05-01.jpg) 1.2 Multi-Index Multi-Index是eosio上的数据库管理接口,通过eosio::multi_index智能合约能够写入、读取和修改eosio数据库的数据。 一个完整的multi_index表定义如下: struct limit_order { uint64_t id; uint128_t price; uint64_t expiration; account_name owner; auto primary_key() const { return id; } uint64_t get_expiration() const { return expiration; } uint128_t get_price() const { return price; } EOSLIB_SERIALIZE( limit_order, ( id )( price )( expiration )( owner ) ) }; 1.3 建立项目框架 使用eosiocpp建立项目框架: cd /contracts eosiocpp -n tictactoe cd tictactoe ll 命令行输出如下: ![eost05-02.png](https://cdn.steemitimages.com/DQmZSxE1yssTRZH2PWE6umR1NC4HXe8AiJcmoND5nFwcdRw/eost05-02.png) 2 编写智能合约 2.1 编写hpp文件 引入标准库,编写基本结构 #include <eosiolib/eosio.hpp> class tictactoe : public eosio::contract { public: tictactoe( account_name self ):contract(self){} //...游戏数据定义... //...游戏命令定义... }; 游戏数据定义,参看1.2 Multi-Index。 struct game { static const uint16_t board_width = 3; static const uint16_t board_height = 3; game() { initialize_board(); } account_name challenger; //挑战者 account_name host; //主角 account_name turn; // 当前角色 host/challenger account_name winner = N(none); // none/draw/name of host/name of challenger std::vector board; // 初始化棋盘 void initialize_board() { board = std::vector(board_width * board_height, 0); } // 初始化游戏 voidreset_game() { initialize_board(); turn = host; winner = N(none); } auto primary_key() const { return challenger; } EOSLIB_SERIALIZE( game, (challenger)(host)(turn)(winner)(board)) }; typedef eosio::multi_index< N(games), game> games; 游戏命令定义 /// @abi action /// 创建新游戏 void create(const account_name& challenger,const account_name& host); /// @abi action /// 重新开始游戏 void restart(const account_name& challenger, const account_name& host,const account_name& by); /// @abi action /// 结束游戏 void close(const account_name& challenger,const account_name& host); /// @abi action /// 下棋 void move(const account_name& challenger,const account_name& host,const account_name& by,const uint16_t& row,const uint16_t& column); hpp的完整源文件可以查看官方的github代码库: https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.hpp 本教程为避免代码文件冲突,仅修改tic_tac_toe为tictactoe 2.2 编写cpp文件 编写基本结构 #include "tictactoe.hpp" using namespace eosio; 创建新游戏: void tictactoe::create(const account_name& challenger, const account_name& host) { //验证主角签名 require_auth(host); //验证主角和挑战者不是同一人 eosio_assert(challenger != host, "challenger shouldn't be the same as host"); //验证主角和挑战者当前没有游戏 games existing_host_games(_self, host); auto itr = existing_host_games.find( challenger ); eosio_assert(itr == existing_host_games.end(), "game already exists"); //初始化游戏 existing_host_games.emplace(host, [&]( auto& g ) { g.challenger = challenger; g.host = host; g.turn = host; }); } 重新开始游戏: void tictactoe::restart(const account_name& challenger, const account_name& host, const account_name& by) { //验证请求者签名 require_auth(by); //验证这场游戏是否存在 games existing_host_games(_self, host); auto itr = existing_host_games.find( challenger ); eosio_assert(itr != existing_host_games.end(), "game doesn't exists"); //验证请求者是不是主角或者挑战者 eosio_assert(by == itr->host || by == itr->challenger, "this is not your game!"); //重新开始游戏 existing_host_games.modify(itr, itr->host, []( auto& g ) { g.reset_game(); }); } 结束游戏: void tictactoe::close(const account_name& challenger, const account_name& host) { //验证主角签名 require_auth(host); //验证这场游戏是否存在 games existing_host_games(_self, host); auto itr = existing_host_games.find( challenger ); eosio_assert(itr != existing_host_games.end(), "game doesn't exists"); //删除游戏 existing_host_games.erase(itr); } 下棋: void tictactoe::move(const account_name& challenger, const account_name& host, const account_name& by, const uint16_t& row, const uint16_t& column ) { //验证请求者签名 require_auth(by); //验证这场游戏是否存在 games existing_host_games(_self, host); auto itr = existing_host_games.find( challenger ); eosio_assert(itr != existing_host_games.end(), "game doesn't exists"); //验证游戏没有结束 eosio_assert(itr->winner == N(none), "the game has ended!"); //验证请求者是不是主角或者挑战者 eosio_assert(by == itr->host || by == itr->challenger, "this is not your game!"); //验证是不是轮到请求者下棋 eosio_assert(by == itr->turn, "it's not your turn yet!"); //验证这一步棋子是不是下在空的棋盘格子 //is_valid_movement方法提取出来,在后面单独写 eosio_assert(is_valid_movement(row, column, itr->board), "not a valid movement!"); //记录这一步下棋数据 const uint8_t cell_value = itr->turn == itr->host ? 1 : 2; const auto turn = itr->turn == itr->host ? itr->challenger : itr->host; existing_host_games.modify(itr, itr->host, [&]( auto& g ) { g.board[row * tictactoe::game::board_width + column] = cell_value; g.turn = turn; //验证这一步棋,是不是赢了比赛 //赢家验证get_winner方法提取出来,在后面单独写 g.winner = get_winner(g); }); } 下棋步数有效验证方法is_valid_movement bool is_empty_cell (const uint8_t& cell) { return cell == 0; } bool is_valid_movement (const uint16_t& row, const uint16_t& column, const vector<uint8_t>& board) { uint32_t movement_location = row * tictactoe::game::board_width + column; bool is_valid = movement_location < board.size() && is_empty_cell(board[movement_location]); return is_valid; } 赢家验证 游戏规则:在横向、纵向和对角线任意一个方向上连线三点就赢得比赛。 account_name get_winner (const tictactoe::game& current_game) { auto& board = current_game.board; bool is_board_full = true; //采用&操作符来计算横向、纵向和对角线上的连线值。 //3 == 0b11, 2 == 0b10, 1 = 0b01, 0 = 0b00 vector consecutive_column(tictactoe::game::board_width, 3 ); vector consecutive_row(tictactoe::game::board_height, 3 ); uint32_t consecutive_diagonal_backslash = 3; uint32_t consecutive_diagonal_slash = 3; for (uint32_t i = 0; i < board.size(); i++) { is_board_full &= is_empty_cell(board[i]); uint16_t row = uint16_t(i / tictactoe::game::board_width); uint16_t column = uint16_t(i % tictactoe::game::board_width); //计算横向和纵向的连线值 consecutive_row[column] = consecutive_row[column] & board[i]; consecutive_column[row] = consecutive_column[row] & board[i]; //计算对角线的连线值 if (row == column) { consecutive_diagonal_backslash = consecutive_diagonal_backslash & board[i]; } if ( row + column == tictactoe::game::board_width - 1) { consecutive_diagonal_slash = consecutive_diagonal_slash & board[i]; } } //检查所有横向、纵向和对角线的连线值并决定赢家 vector aggregate = { consecutive_diagonal_backslash, consecutive_diagonal_slash }; aggregate.insert(aggregate.end(), consecutive_column.begin(), consecutive_column.end()); aggregate.insert(aggregate.end(), consecutive_row.begin(), consecutive_row.end()); for (auto value: aggregate) { if (value == 1) { return current_game.host; } else if (value == 2) { return current_game.challenger; } } // 检查是否已有赢家,有就返回 return is_board_full ? N(draw) : N(none); } cpp的完整源文件可以查看官方的github代码库: https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.cpp 本教程为避免代码文件冲突,仅修改tic_tac_toe为tictactoe 3 编译和运行智能合约 3.1 编译合约 eosiocpp -o tictactoe.wast tictactoe.cpp eosiocpp -g tictactoe.abi tictactoe.cpp ll 命令行输出如下: ![eost05-03.png](https://cdn.steemitimages.com/DQmV1uHvnZyiV1mwETq6E9ZuNtvgY5yDJspdpq4zzQr4xAN/eost05-03.png) 3.2 创建合约账户tttaccount 解锁xiao钱包,创建公钥-私钥对,导入公钥-私钥对到钱包,最后,用公钥创建tttaccount。 具体步骤不再赘述,不熟悉的可以翻看以前的教程。 tttaccount创建后命令行输出如下: ![eost05-04.png](https://cdn.steemitimages.com/DQmZrnH9Qke8cvsXGre5xWruvcGmXN3gvFPoBt3YaceheqX/eost05-04.png) 3.3 上传合同到账户 cleos set contract tttaccount /contracts/tictactoe -p tttaccount@active 命令行输出如下: ![eost05-05.png](https://cdn.steemitimages.com/DQmStU274bvKVMaUZfLNbw3HR1JiUYhcSU5ytFn3WGB6spS/eost05-05.png) 3.4 运行智能合约 创建游戏 cleos push action tttaccount create '{"challenger":"xiaoaccount", "host":"tttaccount"}' -p tttaccount@active 命令行输出如下: ![eost05-06.png](https://cdn.steemitimages.com/DQmPE54crVEza13CfEwHELXD1M2tSiUjcq74KPyhm6jSYXy/eost05-06.png) 下棋 cleos push action tttaccount move '{"challenger":"xiaoaccount", "host":"tttaccount", "by":"tttaccount", "row":0, "column":0}' --permission tttaccount@active cleos push action tttaccount move '{"challenger":"xiaoaccount", "host":"tttaccount", "by":"xiaoaccount", "row":1, "column":1}' --permission xiaoaccount@active 命令行输出如下: ![eost05-07.png](https://cdn.steemitimages.com/DQmfXHQ5fYc2Ptrnw4aUDANWBxKXj6wPGaXrEKwDQhLeYVT/eost05-07.png) 查看游戏状态数据: cleos get table tttaccount tttaccount games 命令行输出如下: ![eost05-8.png](https://cdn.steemitimages.com/DQmRFWdQ1EGKDRxFWH9A1EBgAPJ3g5XFAnfoL3P9mir8W6d/eost05-8.png) 重新开始游戏 cleos push action tttaccount restart '{"challenger":"xiaoaccount", "host":"tttaccount", "by":"tttaccount"}' --permission tttaccount@active 命令行输出如下: ![eost05-9.png](https://cdn.steemitimages.com/DQmYYXAftVn2vTFwSweAKNe7RiPovA9KeSnpetmkDKEKJ7a/eost05-9.png) 结束游戏 cleos push action tttaccount close '{"challenger":"xiaoaccount", "host":"tttaccount"}' --permission tttaccount@active 命令行输出如下: ![eost05-10.png](https://cdn.steemitimages.com/DQmXb5GugmWWPis58NwJDVgJEXBABM2H1Yzp9gQqCEwcWsu/eost05-10.png) 4 后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: 三连棋教程: https://developers.eos.io/eosio-cpp/docs/tic-tac-toe-tutorial 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain","include"],"users":["abi"],"image":["https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg","https://cdn.steemitimages.com/DQmdussHfbdCMBxDqXseyFeUqEFXS7PeBHkBpDA4wVoKjry/eost05-01.jpg","https://cdn.steemitimages.com/DQmZSxE1yssTRZH2PWE6umR1NC4HXe8AiJcmoND5nFwcdRw/eost05-02.png","https://cdn.steemitimages.com/DQmV1uHvnZyiV1mwETq6E9ZuNtvgY5yDJspdpq4zzQr4xAN/eost05-03.png","https://cdn.steemitimages.com/DQmZrnH9Qke8cvsXGre5xWruvcGmXN3gvFPoBt3YaceheqX/eost05-04.png","https://cdn.steemitimages.com/DQmStU274bvKVMaUZfLNbw3HR1JiUYhcSU5ytFn3WGB6spS/eost05-05.png","https://cdn.steemitimages.com/DQmPE54crVEza13CfEwHELXD1M2tSiUjcq74KPyhm6jSYXy/eost05-06.png","https://cdn.steemitimages.com/DQmfXHQ5fYc2Ptrnw4aUDANWBxKXj6wPGaXrEKwDQhLeYVT/eost05-07.png","https://cdn.steemitimages.com/DQmRFWdQ1EGKDRxFWH9A1EBgAPJ3g5XFAnfoL3P9mir8W6d/eost05-8.png","https://cdn.steemitimages.com/DQmYYXAftVn2vTFwSweAKNe7RiPovA9KeSnpetmkDKEKJ7a/eost05-9.png","https://cdn.steemitimages.com/DQmXb5GugmWWPis58NwJDVgJEXBABM2H1Yzp9gQqCEwcWsu/eost05-10.png"],"links":["https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.hpp","https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.cpp","https://developers.eos.io/eosio-cpp/docs/tic-tac-toe-tutorial"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #27487047/Trx 9caf4f39b995254f867020416bb652045d78f8b9
View Raw JSON Data
{
  "trx_id": "9caf4f39b995254f867020416bb652045d78f8b9",
  "block": 27487047,
  "trx_in_block": 7,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-11-07T09:08:45",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "5e4rap-eos",
      "title": "手把手教你玩eos:编写智能合约游戏——三连棋",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n![999.jpg](https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg)\n\n0. 引言\n\n0.1 教程概况\n\n手把手教你学eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n\n本文是第五篇,主要是如何使用eos智能合约编写一个游戏:三连棋。\n\n\n\n0.2 学习内容\n\n1.相关准备知识\n\n2.编写智能合约\n\n3.编译和运行智能合约\n\n\n\n0.3 机器环境\n\ncpu: 1核\n\n内存: 2G\n\n操作系统:CentOS 7.4 64位\n\n服务器所在地:香港\n\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n提示:以下命令行默认在root权限下执行。如遇权限问题,请在命令前加sudo。\n\n\n\n1. 相关准备知识\n\n1.1 三连棋游戏规则\n\n三连棋,又称“井字棋”,是棋类的一种,棋盘为九宫格,呈“井”字形,玩家双方各代表○或×,在棋盘上任意一方连成三个(横竖斜均可)就胜利了。\n\n![eost05-01.jpg](https://cdn.steemitimages.com/DQmdussHfbdCMBxDqXseyFeUqEFXS7PeBHkBpDA4wVoKjry/eost05-01.jpg)\n\n\n1.2 Multi-Index\n\nMulti-Index是eosio上的数据库管理接口,通过eosio::multi_index智能合约能够写入、读取和修改eosio数据库的数据。\n\n一个完整的multi_index表定义如下:\n\nstruct limit_order {\n\n           uint64_t     id;\n\n           uint128_t    price;\n\n           uint64_t     expiration;\n\n           account_name owner;\n\n\n\n           auto primary_key() const { return id; }\n\n           uint64_t get_expiration() const { return expiration; }\n\n           uint128_t get_price() const { return price; }\n\n\n\n           EOSLIB_SERIALIZE( limit_order, ( id )( price )( expiration )( owner ) )\n\n};\n\n\n\n1.3 建立项目框架\n\n使用eosiocpp建立项目框架:\n\ncd /contracts\n\neosiocpp -n tictactoe\n\ncd tictactoe\n\nll\n\n\n\n命令行输出如下:\n\n![eost05-02.png](https://cdn.steemitimages.com/DQmZSxE1yssTRZH2PWE6umR1NC4HXe8AiJcmoND5nFwcdRw/eost05-02.png)\n\n2 编写智能合约\n\n2.1 编写hpp文件\n\n引入标准库,编写基本结构\n\n#include <eosiolib/eosio.hpp>\n\n\n\nclass tictactoe : public eosio::contract {\n\n\n\n           public:\n\n                      tictactoe( account_name self ):contract(self){}\n\n\t\n\n           //...游戏数据定义...\n\n\n\n           //...游戏命令定义...\n\n\t\n\n};\n\n\n\n游戏数据定义,参看1.2 Multi-Index。\n\nstruct game {\n\n            static const uint16_t board_width = 3;\n\n            static const uint16_t board_height = 3;\n\n            game() { \n\n                   initialize_board(); \n\n             }\n\n             account_name   challenger; //挑战者\n\n             account_name   host;       //主角\n\n             account_name   turn; // 当前角色 host/challenger\n\n             account_name   winner = N(none); // none/draw/name of host/name of challenger\n\n             std::vector    board;\n\n\n\n              // 初始化棋盘\n\n              void initialize_board() {\n\n                  board = std::vector(board_width * board_height, 0);\n\n               }\n\n\n\n               // 初始化游戏\n\n               voidreset_game() {\n\n                    initialize_board();\n\n                    turn = host;\n\n                    winner = N(none);\n\n                }\n\n\n\n                auto primary_key() const { return challenger; }\n\n                EOSLIB_SERIALIZE( game, (challenger)(host)(turn)(winner)(board))\n\n         };\n\n\n\ntypedef eosio::multi_index< N(games), game> games;\n\n\n\n游戏命令定义\n\n/// @abi action\n\n      /// 创建新游戏\n\n      void create(const account_name& challenger,const account_name& host);\n\n\n\n       /// @abi action\n\n       /// 重新开始游戏\n\n       void restart(const account_name& challenger, const account_name& host,const account_name& by);\n\n\n\n        /// @abi action\n\n        /// 结束游戏\n\n        void close(const account_name& challenger,const account_name& host);\n\n\n\n         /// @abi action\n\n         /// 下棋\n\n         void move(const account_name& challenger,const account_name& host,const account_name& by,const uint16_t& row,const uint16_t& column);\n\n\n\nhpp的完整源文件可以查看官方的github代码库:\n\nhttps://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.hpp\n\n本教程为避免代码文件冲突,仅修改tic_tac_toe为tictactoe\n\n\n\n2.2 编写cpp文件\n\n编写基本结构\n\n\n\n#include \"tictactoe.hpp\"\n\n\n\nusing namespace eosio;\n\n\n\n创建新游戏:\n\n\t\n\nvoid tictactoe::create(const account_name& challenger, const account_name& host) {\n\n  \t\t\n\n            //验证主角签名\n\n            require_auth(host);\n\n\n\n             //验证主角和挑战者不是同一人\n\n             eosio_assert(challenger != host, \"challenger shouldn't be the same as host\");\n\n\n\n              //验证主角和挑战者当前没有游戏\n\n             games existing_host_games(_self, host);\n\n              auto itr = existing_host_games.find( challenger );\n\n              eosio_assert(itr == existing_host_games.end(), \"game already exists\");\n\n\t\n\n               //初始化游戏\n\n               existing_host_games.emplace(host, [&]( auto& g ) {\n\n     \t           g.challenger = challenger;\n\n     \t           g.host = host;\n\n     \t           g.turn = host;\n\n\t});\n\n}\n\n\n\n重新开始游戏:\n\nvoid tictactoe::restart(const account_name& challenger, const account_name& host, const account_name& by) {\n\n\n\n            //验证请求者签名\n\n            require_auth(by);\n\n\n\n             //验证这场游戏是否存在\n\n             games existing_host_games(_self, host);\n\n             auto itr = existing_host_games.find( challenger );\n\n             eosio_assert(itr != existing_host_games.end(), \"game doesn't exists\");\n\n\n\n              //验证请求者是不是主角或者挑战者\n\n              eosio_assert(by == itr->host || by == itr->challenger, \"this is not your game!\");\n\n\n\n              //重新开始游戏\n\n              existing_host_games.modify(itr, itr->host, []( auto& g ) {\n\n     \t          g.reset_game();\n\n               });\n\n}\n\n\n\n结束游戏:\n\nvoid tictactoe::close(const account_name& challenger, const account_name& host) {\n\n  \n\n            //验证主角签名\n\n            require_auth(host);\n\n\n\n     //验证这场游戏是否存在\n\n     games existing_host_games(_self, host);\n\n     auto itr = existing_host_games.find( challenger );\n\n     eosio_assert(itr != existing_host_games.end(), \"game doesn't exists\");\n\n\n\n      //删除游戏\n\n      existing_host_games.erase(itr);\n\n}\n\n\n\n下棋:\n\nvoid tictactoe::move(const account_name& challenger, const account_name& host, const account_name& by, const uint16_t& row, const uint16_t& column ) {\n\n\n\n      //验证请求者签名\n\n      require_auth(by);\n\n\n\n      //验证这场游戏是否存在\n\n      games existing_host_games(_self, host);\n\n      auto itr = existing_host_games.find( challenger );\n\n      eosio_assert(itr != existing_host_games.end(), \"game doesn't exists\");\n\n\n\n       //验证游戏没有结束\n\n       eosio_assert(itr->winner == N(none), \"the game has ended!\");\n\n\n\n       //验证请求者是不是主角或者挑战者\n\n       eosio_assert(by == itr->host || by == itr->challenger, \"this is not your game!\");\n\n   \n\n       //验证是不是轮到请求者下棋\n\n       eosio_assert(by == itr->turn, \"it's not your turn yet!\");\n\n\n\n\n\n       //验证这一步棋子是不是下在空的棋盘格子\n\n       //is_valid_movement方法提取出来,在后面单独写\n\n       eosio_assert(is_valid_movement(row, column, itr->board), \"not a valid movement!\");\n\n\n\n       //记录这一步下棋数据\n\n       const uint8_t cell_value = itr->turn == itr->host ? 1 : 2;\n\n       const auto turn = itr->turn == itr->host ? itr->challenger : itr->host;\n\n       existing_host_games.modify(itr, itr->host, [&]( auto& g ) {\n\n           g.board[row * tictactoe::game::board_width + column] = cell_value;\n\n           g.turn = turn;\n\n\t  //验证这一步棋,是不是赢了比赛\n\n\t  //赢家验证get_winner方法提取出来,在后面单独写\n\n           g.winner = get_winner(g);\n\n     });\n\n}\n\n\n\n\t\n\n下棋步数有效验证方法is_valid_movement\n\nbool is_empty_cell (const uint8_t& cell) {\n\n      return cell == 0;\n\n}\n\n\n\nbool is_valid_movement (const uint16_t& row, const uint16_t& column, const vector<uint8_t>& board) {\n\n      uint32_t movement_location = row * tictactoe::game::board_width + column;\n\n      bool is_valid = movement_location < board.size() && is_empty_cell(board[movement_location]);\n\n      return is_valid;\n\n}\n\n\n\n赢家验证\n\n游戏规则:在横向、纵向和对角线任意一个方向上连线三点就赢得比赛。\n\naccount_name get_winner (const tictactoe::game& current_game) {\n\n     auto& board = current_game.board;\n\n\n\n     bool is_board_full = true;\n\n\n\n      //采用&操作符来计算横向、纵向和对角线上的连线值。\n\n      //3 == 0b11, 2 == 0b10, 1 = 0b01, 0 = 0b00\n\n      vector consecutive_column(tictactoe::game::board_width, 3 );\n\n      vector consecutive_row(tictactoe::game::board_height, 3 );\n\n      uint32_t consecutive_diagonal_backslash = 3;\n\n      uint32_t consecutive_diagonal_slash = 3;\n\n      for (uint32_t i = 0; i < board.size(); i++) {\n\n           is_board_full &= is_empty_cell(board[i]);\n\n           uint16_t row = uint16_t(i / tictactoe::game::board_width);\n\n           uint16_t column = uint16_t(i % tictactoe::game::board_width);\n\n\n\n            //计算横向和纵向的连线值\n\n            consecutive_row[column] = consecutive_row[column] & board[i]; \n\n            consecutive_column[row] = consecutive_column[row] & board[i];\n\n\n\n            //计算对角线的连线值\n\n            if (row == column) {\n\n               consecutive_diagonal_backslash = consecutive_diagonal_backslash & board[i];\n\n            }\t     \n\n            if ( row + column == tictactoe::game::board_width - 1) {\n\n               consecutive_diagonal_slash = consecutive_diagonal_slash & board[i]; \n\n            }\n\n     }\n\n\n\n     //检查所有横向、纵向和对角线的连线值并决定赢家\n\n     vector aggregate = { consecutive_diagonal_backslash, consecutive_diagonal_slash };\n\n     aggregate.insert(aggregate.end(), consecutive_column.begin(), consecutive_column.end());\n\n     aggregate.insert(aggregate.end(), consecutive_row.begin(), consecutive_row.end());\n\n     for (auto value: aggregate) {\n\n         if (value == 1) {\n\n             return current_game.host;\n\n         } else if (value == 2) {\n\n             return current_game.challenger;\n\n         }\n\n     }\n\n\n\n     // 检查是否已有赢家,有就返回\n\n     return is_board_full ? N(draw) : N(none);\n\n}\n\n\n\ncpp的完整源文件可以查看官方的github代码库:\n\nhttps://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.cpp\n\n本教程为避免代码文件冲突,仅修改tic_tac_toe为tictactoe\n\n\n\n3 编译和运行智能合约\n\n3.1 编译合约\n\neosiocpp -o tictactoe.wast tictactoe.cpp\n\neosiocpp -g tictactoe.abi tictactoe.cpp\n\nll\n\n\n\n命令行输出如下:\n\n![eost05-03.png](https://cdn.steemitimages.com/DQmV1uHvnZyiV1mwETq6E9ZuNtvgY5yDJspdpq4zzQr4xAN/eost05-03.png)\n\n\n3.2 创建合约账户tttaccount\n\n解锁xiao钱包,创建公钥-私钥对,导入公钥-私钥对到钱包,最后,用公钥创建tttaccount。\n\n具体步骤不再赘述,不熟悉的可以翻看以前的教程。\n\n\n\ntttaccount创建后命令行输出如下:\n\n\n![eost05-04.png](https://cdn.steemitimages.com/DQmZrnH9Qke8cvsXGre5xWruvcGmXN3gvFPoBt3YaceheqX/eost05-04.png)\n\n\n3.3 上传合同到账户\n\ncleos set contract tttaccount /contracts/tictactoe -p tttaccount@active\n\n\n\n命令行输出如下:\n\n\n![eost05-05.png](https://cdn.steemitimages.com/DQmStU274bvKVMaUZfLNbw3HR1JiUYhcSU5ytFn3WGB6spS/eost05-05.png)\n\n\n3.4 运行智能合约\n\n创建游戏\n\ncleos push action tttaccount create '{\"challenger\":\"xiaoaccount\", \"host\":\"tttaccount\"}' -p tttaccount@active\n\n\n\n命令行输出如下:\n\n![eost05-06.png](https://cdn.steemitimages.com/DQmPE54crVEza13CfEwHELXD1M2tSiUjcq74KPyhm6jSYXy/eost05-06.png)\n\n下棋\n\ncleos push action tttaccount move '{\"challenger\":\"xiaoaccount\", \"host\":\"tttaccount\", \"by\":\"tttaccount\", \"row\":0, \"column\":0}' --permission tttaccount@active\n\n\n\ncleos push action tttaccount move '{\"challenger\":\"xiaoaccount\", \"host\":\"tttaccount\", \"by\":\"xiaoaccount\", \"row\":1, \"column\":1}' --permission xiaoaccount@active\n\n\n\n命令行输出如下:\n![eost05-07.png](https://cdn.steemitimages.com/DQmfXHQ5fYc2Ptrnw4aUDANWBxKXj6wPGaXrEKwDQhLeYVT/eost05-07.png)\n\n\n查看游戏状态数据:\n\ncleos get table tttaccount tttaccount games\n\n\n\n命令行输出如下:\n![eost05-8.png](https://cdn.steemitimages.com/DQmRFWdQ1EGKDRxFWH9A1EBgAPJ3g5XFAnfoL3P9mir8W6d/eost05-8.png)\n\n\n重新开始游戏\n\ncleos push action tttaccount restart '{\"challenger\":\"xiaoaccount\", \"host\":\"tttaccount\", \"by\":\"tttaccount\"}' --permission tttaccount@active\n\n\n\n命令行输出如下:\n\n![eost05-9.png](https://cdn.steemitimages.com/DQmYYXAftVn2vTFwSweAKNe7RiPovA9KeSnpetmkDKEKJ7a/eost05-9.png)\n\n结束游戏\n\ncleos push action tttaccount close '{\"challenger\":\"xiaoaccount\", \"host\":\"tttaccount\"}' --permission tttaccount@active\n\n\n\n命令行输出如下:\n\n![eost05-10.png](https://cdn.steemitimages.com/DQmXb5GugmWWPis58NwJDVgJEXBABM2H1Yzp9gQqCEwcWsu/eost05-10.png)\n\n4 后记\n\n延伸阅读\n\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n\n三连棋教程: https://developers.eos.io/eosio-cpp/docs/tic-tac-toe-tutorial\n\n\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\",\"include\"],\"users\":[\"abi\"],\"image\":[\"https://cdn.steemitimages.com/DQmV5NbMReUXLBRfdfvY3UTNQxMnZxEGSVrAZgtRiwe1gTc/999.jpg\",\"https://cdn.steemitimages.com/DQmdussHfbdCMBxDqXseyFeUqEFXS7PeBHkBpDA4wVoKjry/eost05-01.jpg\",\"https://cdn.steemitimages.com/DQmZSxE1yssTRZH2PWE6umR1NC4HXe8AiJcmoND5nFwcdRw/eost05-02.png\",\"https://cdn.steemitimages.com/DQmV1uHvnZyiV1mwETq6E9ZuNtvgY5yDJspdpq4zzQr4xAN/eost05-03.png\",\"https://cdn.steemitimages.com/DQmZrnH9Qke8cvsXGre5xWruvcGmXN3gvFPoBt3YaceheqX/eost05-04.png\",\"https://cdn.steemitimages.com/DQmStU274bvKVMaUZfLNbw3HR1JiUYhcSU5ytFn3WGB6spS/eost05-05.png\",\"https://cdn.steemitimages.com/DQmPE54crVEza13CfEwHELXD1M2tSiUjcq74KPyhm6jSYXy/eost05-06.png\",\"https://cdn.steemitimages.com/DQmfXHQ5fYc2Ptrnw4aUDANWBxKXj6wPGaXrEKwDQhLeYVT/eost05-07.png\",\"https://cdn.steemitimages.com/DQmRFWdQ1EGKDRxFWH9A1EBgAPJ3g5XFAnfoL3P9mir8W6d/eost05-8.png\",\"https://cdn.steemitimages.com/DQmYYXAftVn2vTFwSweAKNe7RiPovA9KeSnpetmkDKEKJ7a/eost05-9.png\",\"https://cdn.steemitimages.com/DQmXb5GugmWWPis58NwJDVgJEXBABM2H1Yzp9gQqCEwcWsu/eost05-10.png\"],\"links\":[\"https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.hpp\",\"https://github.com/EOSIO/eos/blob/master/contracts/tic_tac_toe/tic_tac_toe.cpp\",\"https://developers.eos.io/eosio-cpp/docs/tic-tac-toe-tutorial\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
eoswingpublished a new post: eos-helloeos
2018/10/30 09:02:33
parent author
parent permlinkeos
authoreoswing
permlinkeos-helloeos
title手把手教你玩eos:编写第一个智能合约Hello_eos
body文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。 0.引言 0.1教程概况 手把手教你学eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。 本文是第四篇,主要是通过一个简单的HelloWorld来讲解如何编写EOS智能合约。 0.2 学习内容 1.相关准备知识 2.编写智能合约hello_eos.cpp 3.编译和运行智能合约 4.添加身份验证 0.3 机器环境 ●cpu: 1核 ●内存: 2G ●操作系统:CentOS 7.4 64位 ●服务器所在地:香港 推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。 提示:以下命令行默认在root权限下执行。如遇权限问题,请在命令前加sudo。 1.相关准备知识 1.1 C++语言经验 基于EOSIO的区块链使用WebAssembly(WASM)执行用户生成的应用程序和代码。 C++是EOS官方推荐的主要智能合约开发语言。 当然,如果你不会C++也没关系,毕竟入门学习智能合约开发,需要掌握的C++知识并不多。 但是,最好要有一种编译型语言的学习经验。 1.2 相关术语规则 操作(action)和类型(type)定义 EOSIO智能合约由一组动作(action)和类型(type)定义组成。 ●action 动作定义指定并实现合同的行为。 ●type 类型定义指定所需的内容和结构。 EOSIO操作主要在基于消息的通信体系结构中运行。 客户端通过发送(推送)消息来调用操作nodeos。 可以使用cleos命令完成,也可以使用EOSIO send方法之一(例如eosio::action::send)完成。 内联(Inline)和延迟(Deferred) EOSIO支持两种基本通信模型,内联(Inline)和延迟(Deferred)。 ●Inline 内联,意思就是直接采用内部函数体发起,调用其他函数的方式。这可以保证交易无阻碍执行,不必通知外部失败或者成功结果,同时内联也可保证交易始终处于同一作用域以及权限。 ●Deferred 延迟,通过生产者的判定来决定延后按时执行,可能会发生timeout的问题。这种方式可以跨多个作用域工作,并且可以携带着发送给它的合约权限。 动作(action)和交易(transaction) ●action是一个动作,账户和合约交互是通过action,可以单独发送一个action。 ●Transaction是一组动作。所有action都必须成功,该Transaction才会成功。 收到一个交易并不意味着这个交易已经被确认,它仅仅说明这个交易被一个BP节点接受并且没有错误,当然也意味着很有可能这个交易被其他bp接受了。当一个交易被包含在一个块当中的时候,它才是可以被确认执行的。 2.编写智能合约hello_eos.cpp 2.1 创建hello_eos智能合约目录框架 使用eosiocpp工具生成框架 进入/contracts文件夹用eosiocpp工具生成hello_eos智能合约目录框架。 eosiocpp是eos自带的一个智能合约开发工具。 先后输入如下命令: 1 cd /contracts 2 eosiocpp -n hello_eos 3 cd hello_eos 4 ll 命令行输出如下: ![eost04-01.png](https://cdn.steemitimages.com/DQmd6JsurqYHxQnqfrhbKyKJ3Vq7TgmyQM1cv2NoqQCArrT/eost04-01.png) cpp和hpp文件 可以看到,在hello_eos文件夹中已经自动生成了两个文件hello_eos.hpp和hello_eos.cpp。 ●hello_eos.hpp是头文件,包含文件引用的变量,常量和函数。这里主要引用了eosiolib/eosio.hpp这个库文件。 ●hello_eos.cpp就是包含合约实现方法的源文件。 2.2 编辑hello_eos.cpp源文件 eosiocpp生成的hello_eos.cpp文件里已经生成了一些模板内容。 里面有一个hi方法,主要是打印命令请求中传递的参数。 下面我们修改其中打印语句。 将 print(“Hello, “,name{user});修改为print(“Hello,eosfans: “,name{user}); vi hello_eos.cpp 输入i进行编辑,编辑后的hello_eos.cpp文件内容如下: ![eost04-02.png](https://cdn.steemitimages.com/DQmXSHmrDouwjsgByFenNuGrhsgp8kYRRELPjLHC9DCEEbC/eost04-02.png) 按esc键退出编辑模式后,输入 :wq 后保存退出。 为了极简演示一个合约的编写、编译和运行流程,这个cpp文件只是简单的日志打印,没有引入包括权限,签名等复杂度。 3.编译和运行智能合约 3.1 编译wast文件 wast文件是WASM适用的由cpp文件编译后的文件格式,这是区块链接收的唯一格式。 eosiocpp -o /contracts/hello_eos/hello_eos.wast /contracts/hello_eos/hello_eos.cpp 命令行输出如下: ![eost04-03.png](https://cdn.steemitimages.com/DQmYXTdVNaHXPdYr2Z7u6Jej6Kwn3VS7RenHnw18fJVfzg5/eost04-03.png) 3.2 编译abi文件 abi是一个json格式的,用来描述智能合约如何在action和二进制程序中进行转变的方法,也用来描述数据库状态。有了abi来描述你的智能合约,开发者和用户都可以通过JSON无缝地与合约进行交互。 eosiocpp -g /contracts/hello_eos/hello_eos.abi /contracts/hello_eos/hello_eos.cpp 命令行输出如下: ![eost04-04.png](https://cdn.steemitimages.com/DQmPNPWM3MEZ7zWhzN9FN6YrMmc2BSdFCrmcn5jv65arqhC/eost04-04.png) 查看hello_eos目录 ![eost04-05.png](https://cdn.steemitimages.com/DQmYn8RxDQwKVM4ag6esdHCRWMGDV7GU7rBxCKUKGpTTHz6/eost04-05.png) 3.3 创建helloaccount账户 创建公钥私钥对: ![eost04-06.png](https://cdn.steemitimages.com/DQmUfamkDDUQaMx3HrszZe4SD2brjiAfhadYNfH1NzPty7N/eost04-06.png) 添加秘钥到xiao钱包: ![eost04-07.png](https://cdn.steemitimages.com/DQmY7AbuZDq6vMUgbsRAqnWhNjtuypd7jbZV2yymMCyMUKf/eost04-07.png) 建立helloaccount账户: ![eost04-08.png](https://cdn.steemitimages.com/DQmT4ZSJNEDSx2ZpqWMuMj7LLYLftq9Sm7iAJVFre5fgEiM/eost04-08.png) 以上相关命令,可以查看第3篇的 2.1 创建合约用账户 3.4 上传合同到账户 cleos set contract helloaccount /contracts/hello_eos -p helloaccount@active 命令行输出如下: ![eost04-09.png](https://cdn.steemitimages.com/DQmdFhG8Aw7kHTdFtNyRwkxMy3mRePg2Cksgxc6bJeczPHe/eost04-09.png) 3.5 运行合同 输入一个模拟用户名 xiao 使用 helloaccount签名授权,测试通过。 cleos push action helloaccount hi '["hello"]' -p helloaccount@active 命令行输出如下: ![eost04-10.png](https://cdn.steemitimages.com/DQmXaWyXDo3a7J4VU8LG9qi5LfucBHKxGJCfPxxfSWLiJub/eost04-10.png) 输入一个模拟用户名 xiao 使用 xiaoaccount签名授权,测试通过。 cleos push action helloaccount hi '["hello"]' -p xiaoaccount@active 命令行输出如下: ![eost04-11.png](https://cdn.steemitimages.com/DQmRCUvvr9w363tQVqzpHPM1wGV8A54m4bpwqqWHAcuysdc/eost04-11.png) 目前我们的hello_eos合约是不限制hi参数的,也就是说其实我们是没有“xiao”这个签名人的。 现在无论这个参数如何输入账户名,无论用哪个账户签名授权,都可以输出。 下面我们在hello_eos中添加身份验证,要求输入的账户名必须要对应的账户来签名授权。 4.添加身份验证 4.1 修改cpp文件 在hello_eos.cpp文件中添加 require_auth(user); 这段代码: ![eost04-12.png](https://cdn.steemitimages.com/DQmcNqMWfazPb8iAMShUh68fZBaRB97Tk2FLYdy6vbUwdCU/eost04-12.png) 4.2 重新编译和部署合同 重复上述编译和部署过程。全部命令行输出如下: ![eost04-13.png](https://cdn.steemitimages.com/DQmcH5J8WoMh5XDSC6t323E2tdzNSYn2mAeakL8WGLrrwMu/eost04-13.png) 4.3 再次运行合同 输入一个模拟用户名 xiao 使用 helloaccount签名授权,测试发现身份验证不通过。 输入账户名 helloaccount 使用 helloaccount签名授权,身份验证通过。 输入账户名 xiaoaccount 使用 xiaoaccount签名授权,身份验证通过。 命令行输出如下: ![eost04-14.png](https://cdn.steemitimages.com/DQmeUcJyRq6vujHNjfv2oWHMNFvqCwkFK4JNDakRPpV2m56/eost04-14.png) hello_eos的身份验证生效。 5.后记 延伸阅读 在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案: ●Hello World合同: https://developers.eos.io/eosio-cpp/docs/hello-world 如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。
json metadata{"tags":["eos","blockchain"],"image":["https://cdn.steemitimages.com/DQmd6JsurqYHxQnqfrhbKyKJ3Vq7TgmyQM1cv2NoqQCArrT/eost04-01.png","https://cdn.steemitimages.com/DQmXSHmrDouwjsgByFenNuGrhsgp8kYRRELPjLHC9DCEEbC/eost04-02.png","https://cdn.steemitimages.com/DQmYXTdVNaHXPdYr2Z7u6Jej6Kwn3VS7RenHnw18fJVfzg5/eost04-03.png","https://cdn.steemitimages.com/DQmPNPWM3MEZ7zWhzN9FN6YrMmc2BSdFCrmcn5jv65arqhC/eost04-04.png","https://cdn.steemitimages.com/DQmYn8RxDQwKVM4ag6esdHCRWMGDV7GU7rBxCKUKGpTTHz6/eost04-05.png","https://cdn.steemitimages.com/DQmUfamkDDUQaMx3HrszZe4SD2brjiAfhadYNfH1NzPty7N/eost04-06.png","https://cdn.steemitimages.com/DQmY7AbuZDq6vMUgbsRAqnWhNjtuypd7jbZV2yymMCyMUKf/eost04-07.png","https://cdn.steemitimages.com/DQmT4ZSJNEDSx2ZpqWMuMj7LLYLftq9Sm7iAJVFre5fgEiM/eost04-08.png","https://cdn.steemitimages.com/DQmdFhG8Aw7kHTdFtNyRwkxMy3mRePg2Cksgxc6bJeczPHe/eost04-09.png","https://cdn.steemitimages.com/DQmXaWyXDo3a7J4VU8LG9qi5LfucBHKxGJCfPxxfSWLiJub/eost04-10.png","https://cdn.steemitimages.com/DQmRCUvvr9w363tQVqzpHPM1wGV8A54m4bpwqqWHAcuysdc/eost04-11.png","https://cdn.steemitimages.com/DQmcNqMWfazPb8iAMShUh68fZBaRB97Tk2FLYdy6vbUwdCU/eost04-12.png","https://cdn.steemitimages.com/DQmcH5J8WoMh5XDSC6t323E2tdzNSYn2mAeakL8WGLrrwMu/eost04-13.png","https://cdn.steemitimages.com/DQmeUcJyRq6vujHNjfv2oWHMNFvqCwkFK4JNDakRPpV2m56/eost04-14.png"],"links":["https://developers.eos.io/eosio-cpp/docs/hello-world"],"app":"steemit/0.1","format":"markdown"}
Transaction InfoBlock #27256704/Trx f3796f5738937da9f5cd62c6c25ddb406473b9be
View Raw JSON Data
{
  "trx_id": "f3796f5738937da9f5cd62c6c25ddb406473b9be",
  "block": 27256704,
  "trx_in_block": 40,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-10-30T09:02:33",
  "op": [
    "comment",
    {
      "parent_author": "",
      "parent_permlink": "eos",
      "author": "eoswing",
      "permlink": "eos-helloeos",
      "title": "手把手教你玩eos:编写第一个智能合约Hello_eos",
      "body": "文章由EOS节点EOSWing(柚翼)首发于eoswing.io博客,内容将不定期更新,仅供学习交流之用。\n\n0.引言\n\n0.1教程概况\n\n手把手教你学eos系列教程,从最基础开始,一步一步教你学会用eos。比如发代币,开发DAPP等等。\n\n本文是第四篇,主要是通过一个简单的HelloWorld来讲解如何编写EOS智能合约。\n\n\n\n0.2 学习内容\n\n1.相关准备知识\n\n2.编写智能合约hello_eos.cpp\n\n3.编译和运行智能合约\n\n4.添加身份验证\n\n\n\n0.3 机器环境\n\n●cpu: 1核\n\n●内存: 2G\n\n●操作系统:CentOS 7.4 64位\n\n●服务器所在地:香港\n\n推荐将服务器放在网络较为优质的环境,比如香港。不然会有很多配置依赖下载上的问题。\n\n提示:以下命令行默认在root权限下执行。如遇权限问题,请在命令前加sudo。\n\n\n\n1.相关准备知识\n\n1.1 C++语言经验\n\n基于EOSIO的区块链使用WebAssembly(WASM)执行用户生成的应用程序和代码。\n\nC++是EOS官方推荐的主要智能合约开发语言。\n\n当然,如果你不会C++也没关系,毕竟入门学习智能合约开发,需要掌握的C++知识并不多。\n\n但是,最好要有一种编译型语言的学习经验。\n\n\n\n1.2 相关术语规则\n\n操作(action)和类型(type)定义\n\nEOSIO智能合约由一组动作(action)和类型(type)定义组成。\n\n●action 动作定义指定并实现合同的行为。\n\n●type 类型定义指定所需的内容和结构。\n\nEOSIO操作主要在基于消息的通信体系结构中运行。\n\n客户端通过发送(推送)消息来调用操作nodeos。\n\n可以使用cleos命令完成,也可以使用EOSIO send方法之一(例如eosio::action::send)完成。\n\n\n\n内联(Inline)和延迟(Deferred)\n\nEOSIO支持两种基本通信模型,内联(Inline)和延迟(Deferred)。\n\n●Inline 内联,意思就是直接采用内部函数体发起,调用其他函数的方式。这可以保证交易无阻碍执行,不必通知外部失败或者成功结果,同时内联也可保证交易始终处于同一作用域以及权限。\n\n●Deferred 延迟,通过生产者的判定来决定延后按时执行,可能会发生timeout的问题。这种方式可以跨多个作用域工作,并且可以携带着发送给它的合约权限。\n\n\n\n动作(action)和交易(transaction)\n\n●action是一个动作,账户和合约交互是通过action,可以单独发送一个action。\n\n●Transaction是一组动作。所有action都必须成功,该Transaction才会成功。\n\n收到一个交易并不意味着这个交易已经被确认,它仅仅说明这个交易被一个BP节点接受并且没有错误,当然也意味着很有可能这个交易被其他bp接受了。当一个交易被包含在一个块当中的时候,它才是可以被确认执行的。\n\n\n\n2.编写智能合约hello_eos.cpp\n\n2.1 创建hello_eos智能合约目录框架\n\n使用eosiocpp工具生成框架\n\n进入/contracts文件夹用eosiocpp工具生成hello_eos智能合约目录框架。\n\neosiocpp是eos自带的一个智能合约开发工具。\n\n先后输入如下命令:\n\n1 cd /contracts\n\n2 eosiocpp -n hello_eos\n\n3 cd hello_eos\n\n4 ll\n\n\n\n命令行输出如下:\n![eost04-01.png](https://cdn.steemitimages.com/DQmd6JsurqYHxQnqfrhbKyKJ3Vq7TgmyQM1cv2NoqQCArrT/eost04-01.png)\n\n\n\n\ncpp和hpp文件\n\n可以看到,在hello_eos文件夹中已经自动生成了两个文件hello_eos.hpp和hello_eos.cpp。\n\n●hello_eos.hpp是头文件,包含文件引用的变量,常量和函数。这里主要引用了eosiolib/eosio.hpp这个库文件。\n\n●hello_eos.cpp就是包含合约实现方法的源文件。\n\n\n\n2.2 编辑hello_eos.cpp源文件\n\neosiocpp生成的hello_eos.cpp文件里已经生成了一些模板内容。\n\n里面有一个hi方法,主要是打印命令请求中传递的参数。\n\n下面我们修改其中打印语句。\n\n将 print(“Hello, “,name{user});修改为print(“Hello,eosfans: “,name{user});\n\nvi hello_eos.cpp\n\n输入i进行编辑,编辑后的hello_eos.cpp文件内容如下:\n![eost04-02.png](https://cdn.steemitimages.com/DQmXSHmrDouwjsgByFenNuGrhsgp8kYRRELPjLHC9DCEEbC/eost04-02.png)\n\n\n按esc键退出编辑模式后,输入 :wq 后保存退出。\n\n为了极简演示一个合约的编写、编译和运行流程,这个cpp文件只是简单的日志打印,没有引入包括权限,签名等复杂度。\n\n\n\n3.编译和运行智能合约\n\n3.1 编译wast文件\n\nwast文件是WASM适用的由cpp文件编译后的文件格式,这是区块链接收的唯一格式。\n\neosiocpp -o /contracts/hello_eos/hello_eos.wast /contracts/hello_eos/hello_eos.cpp\n\n\n\n命令行输出如下:\n![eost04-03.png](https://cdn.steemitimages.com/DQmYXTdVNaHXPdYr2Z7u6Jej6Kwn3VS7RenHnw18fJVfzg5/eost04-03.png)\n\n\n\n\n3.2 编译abi文件\n\nabi是一个json格式的,用来描述智能合约如何在action和二进制程序中进行转变的方法,也用来描述数据库状态。有了abi来描述你的智能合约,开发者和用户都可以通过JSON无缝地与合约进行交互。\n\neosiocpp -g /contracts/hello_eos/hello_eos.abi /contracts/hello_eos/hello_eos.cpp\n\n\n\n命令行输出如下:\n![eost04-04.png](https://cdn.steemitimages.com/DQmPNPWM3MEZ7zWhzN9FN6YrMmc2BSdFCrmcn5jv65arqhC/eost04-04.png)\n\n\n查看hello_eos目录\n![eost04-05.png](https://cdn.steemitimages.com/DQmYn8RxDQwKVM4ag6esdHCRWMGDV7GU7rBxCKUKGpTTHz6/eost04-05.png)\n\n\n\n\n3.3 创建helloaccount账户\n\n创建公钥私钥对:\n![eost04-06.png](https://cdn.steemitimages.com/DQmUfamkDDUQaMx3HrszZe4SD2brjiAfhadYNfH1NzPty7N/eost04-06.png)\n\n\n添加秘钥到xiao钱包:\n![eost04-07.png](https://cdn.steemitimages.com/DQmY7AbuZDq6vMUgbsRAqnWhNjtuypd7jbZV2yymMCyMUKf/eost04-07.png)\n\n\n建立helloaccount账户:\n![eost04-08.png](https://cdn.steemitimages.com/DQmT4ZSJNEDSx2ZpqWMuMj7LLYLftq9Sm7iAJVFre5fgEiM/eost04-08.png)\n\n\n以上相关命令,可以查看第3篇的 2.1 创建合约用账户\n\n\n\n3.4 上传合同到账户\n\ncleos set contract helloaccount /contracts/hello_eos -p helloaccount@active\n\n\n\n命令行输出如下:\n\n![eost04-09.png](https://cdn.steemitimages.com/DQmdFhG8Aw7kHTdFtNyRwkxMy3mRePg2Cksgxc6bJeczPHe/eost04-09.png)\n\n\n\n3.5 运行合同\n\n输入一个模拟用户名 xiao 使用 helloaccount签名授权,测试通过。\n\ncleos push action helloaccount hi '[\"hello\"]' -p helloaccount@active\n\n\n\n命令行输出如下:\n\n![eost04-10.png](https://cdn.steemitimages.com/DQmXaWyXDo3a7J4VU8LG9qi5LfucBHKxGJCfPxxfSWLiJub/eost04-10.png)\n\n输入一个模拟用户名 xiao 使用 xiaoaccount签名授权,测试通过。\n\ncleos push action helloaccount hi '[\"hello\"]' -p xiaoaccount@active\n\n\n\n命令行输出如下:\n![eost04-11.png](https://cdn.steemitimages.com/DQmRCUvvr9w363tQVqzpHPM1wGV8A54m4bpwqqWHAcuysdc/eost04-11.png)\n\n\n目前我们的hello_eos合约是不限制hi参数的,也就是说其实我们是没有“xiao”这个签名人的。\n\n现在无论这个参数如何输入账户名,无论用哪个账户签名授权,都可以输出。\n\n下面我们在hello_eos中添加身份验证,要求输入的账户名必须要对应的账户来签名授权。\n\n\n\n4.添加身份验证\n\n4.1 修改cpp文件\n\n在hello_eos.cpp文件中添加 require_auth(user); 这段代码:\n\n![eost04-12.png](https://cdn.steemitimages.com/DQmcNqMWfazPb8iAMShUh68fZBaRB97Tk2FLYdy6vbUwdCU/eost04-12.png)\n\n\n\n4.2 重新编译和部署合同\n\n重复上述编译和部署过程。全部命令行输出如下:\n\n![eost04-13.png](https://cdn.steemitimages.com/DQmcH5J8WoMh5XDSC6t323E2tdzNSYn2mAeakL8WGLrrwMu/eost04-13.png)\n\n\n\n4.3 再次运行合同\n\n输入一个模拟用户名 xiao 使用 helloaccount签名授权,测试发现身份验证不通过。\n\n输入账户名 helloaccount 使用 helloaccount签名授权,身份验证通过。\n\n输入账户名 xiaoaccount 使用 xiaoaccount签名授权,身份验证通过。\n\n\n\n命令行输出如下:\n![eost04-14.png](https://cdn.steemitimages.com/DQmeUcJyRq6vujHNjfv2oWHMNFvqCwkFK4JNDakRPpV2m56/eost04-14.png)\n\n\nhello_eos的身份验证生效。\n\n\n\n5.后记\n\n延伸阅读\n\n在本文的学习中如果遇到问题,欢迎留言或者在如下链接寻找解决方案:\n\n●Hello World合同: https://developers.eos.io/eosio-cpp/docs/hello-world\n\n\n\n如果觉得这一系列教程有点意思,请投票给柚翼节点(eoswingdotio)。您的投票是本教程持续更新的动力源泉,谢谢。",
      "json_metadata": "{\"tags\":[\"eos\",\"blockchain\"],\"image\":[\"https://cdn.steemitimages.com/DQmd6JsurqYHxQnqfrhbKyKJ3Vq7TgmyQM1cv2NoqQCArrT/eost04-01.png\",\"https://cdn.steemitimages.com/DQmXSHmrDouwjsgByFenNuGrhsgp8kYRRELPjLHC9DCEEbC/eost04-02.png\",\"https://cdn.steemitimages.com/DQmYXTdVNaHXPdYr2Z7u6Jej6Kwn3VS7RenHnw18fJVfzg5/eost04-03.png\",\"https://cdn.steemitimages.com/DQmPNPWM3MEZ7zWhzN9FN6YrMmc2BSdFCrmcn5jv65arqhC/eost04-04.png\",\"https://cdn.steemitimages.com/DQmYn8RxDQwKVM4ag6esdHCRWMGDV7GU7rBxCKUKGpTTHz6/eost04-05.png\",\"https://cdn.steemitimages.com/DQmUfamkDDUQaMx3HrszZe4SD2brjiAfhadYNfH1NzPty7N/eost04-06.png\",\"https://cdn.steemitimages.com/DQmY7AbuZDq6vMUgbsRAqnWhNjtuypd7jbZV2yymMCyMUKf/eost04-07.png\",\"https://cdn.steemitimages.com/DQmT4ZSJNEDSx2ZpqWMuMj7LLYLftq9Sm7iAJVFre5fgEiM/eost04-08.png\",\"https://cdn.steemitimages.com/DQmdFhG8Aw7kHTdFtNyRwkxMy3mRePg2Cksgxc6bJeczPHe/eost04-09.png\",\"https://cdn.steemitimages.com/DQmXaWyXDo3a7J4VU8LG9qi5LfucBHKxGJCfPxxfSWLiJub/eost04-10.png\",\"https://cdn.steemitimages.com/DQmRCUvvr9w363tQVqzpHPM1wGV8A54m4bpwqqWHAcuysdc/eost04-11.png\",\"https://cdn.steemitimages.com/DQmcNqMWfazPb8iAMShUh68fZBaRB97Tk2FLYdy6vbUwdCU/eost04-12.png\",\"https://cdn.steemitimages.com/DQmcH5J8WoMh5XDSC6t323E2tdzNSYn2mAeakL8WGLrrwMu/eost04-13.png\",\"https://cdn.steemitimages.com/DQmeUcJyRq6vujHNjfv2oWHMNFvqCwkFK4JNDakRPpV2m56/eost04-14.png\"],\"links\":[\"https://developers.eos.io/eosio-cpp/docs/hello-world\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
    }
  ]
}
2018/10/24 09:10:12
voterfastresteem
authoreoswing
permlink5m7etd-eos
weight100 (1.00%)
Transaction InfoBlock #27084191/Trx ef326efa3b4e916f5870f40c76830e234aedc0c8
View Raw JSON Data
{
  "trx_id": "ef326efa3b4e916f5870f40c76830e234aedc0c8",
  "block": 27084191,
  "trx_in_block": 17,
  "op_in_trx": 0,
  "virtual_op": 0,
  "timestamp": "2018-10-24T09:10:12",
  "op": [
    "vote",
    {
      "voter": "fastresteem",
      "author": "eoswing",
      "permlink": "5m7etd-eos",
      "weight": 100
    }
  ]
}

Account Metadata

POSTING JSON METADATA
profile{"profile_image":"https://cdn.steemitimages.com/DQmaQM1M6ra6es2eRgwgKgTQ2fDExkGkKSmBfyWXXmJQKiZ/eoswing-logo-256b.png","website":"https://eoswing.io","name":"eoswing"}
JSON METADATA
profile{"profile_image":"https://cdn.steemitimages.com/DQmaQM1M6ra6es2eRgwgKgTQ2fDExkGkKSmBfyWXXmJQKiZ/eoswing-logo-256b.png","website":"https://eoswing.io","name":"eoswing"}
{
  "posting_json_metadata": {
    "profile": {
      "profile_image": "https://cdn.steemitimages.com/DQmaQM1M6ra6es2eRgwgKgTQ2fDExkGkKSmBfyWXXmJQKiZ/eoswing-logo-256b.png",
      "website": "https://eoswing.io",
      "name": "eoswing"
    }
  },
  "json_metadata": {
    "profile": {
      "profile_image": "https://cdn.steemitimages.com/DQmaQM1M6ra6es2eRgwgKgTQ2fDExkGkKSmBfyWXXmJQKiZ/eoswing-logo-256b.png",
      "website": "https://eoswing.io",
      "name": "eoswing"
    }
  }
}

Auth Keys

Owner
Single Signature
Public Keys
STM6yG6ezPfMj8DjrTSLhH8FjBjP1uyZrHteE8siSaxfkCfCguQFz1/1
Active
Single Signature
Public Keys
STM7VzZaD1MTmTRrCxuEaJTf6exRKsncya3gZD6tQd4FwptpWwwj31/1
Posting
Single Signature
Public Keys
STM7yc8CYF437A32GNcG47MG4R26RNQ24tVHcc9Vg7ip93tnaaaJg1/1
Memo
STM6Dw6kWbk4GdGtf3tFBL2ci5egtoyJ3UByF6MVENxXRWU83RMDP
{
  "owner": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
      [
        "STM6yG6ezPfMj8DjrTSLhH8FjBjP1uyZrHteE8siSaxfkCfCguQFz",
        1
      ]
    ]
  },
  "active": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
      [
        "STM7VzZaD1MTmTRrCxuEaJTf6exRKsncya3gZD6tQd4FwptpWwwj3",
        1
      ]
    ]
  },
  "posting": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [
      [
        "STM7yc8CYF437A32GNcG47MG4R26RNQ24tVHcc9Vg7ip93tnaaaJg",
        1
      ]
    ]
  },
  "memo": "STM6Dw6kWbk4GdGtf3tFBL2ci5egtoyJ3UByF6MVENxXRWU83RMDP"
}

Witness Votes

0 / 30
No active witness votes.
[]