目录
区块链原理与技术 1
一、方案设计 1
合约机制 1
账户体系 2
案例 3
数据流图 4
二、存储设计 4
区块链合约存储 4
区块链数据库表结构 5
服务器数据库表结构 6
三、合约核心功能 7
合约事件 7
金融机构和政府机构注册 7
企业注册 8
转账 8
还款 9
四、功能测试 12
创建用户 12
账户审核 12
用户注册 15
给予信用额度 17
企业申请和转移信用凭证 19
返还 20
五、界面展示 22
注册页面 23
管理面板 23
审核面板 24
转账页面 25
确认转账 26
还款页面 27
确认返还 28
查询面板 29
六、心得体会 30
一、方案设计
合约机制
信用凭证
信用凭证指企业间签发的应收账款单据,以及金融机构向车企签发的应收账款单据。简单来说,信用凭证指对企业未来盈利能力的衡量,或者企业债务。应收账款单据包含金额、逾期时间、和收款双方。
信用凭证由债务方向债权方提供,表示债务方在一定时间前将会偿还。因此信用凭证的流动方向和人民币的流动方向相反:若债务方向债权方支付人民币欠款,债权方就要向债务方返还相应的信用凭证。
签发信用凭证
信用凭证分借入和借出。企业在借出信用凭证时(欠债),不能超过自己所拥有的的信用凭证总额(借入-借出),以确保企业不会透支自己的信用。银行在衡量企业的信用评级时,不能只看信用凭证净值,因为信用凭证为 0 时不代表企业不欠钱,企业信用在未来的一段时间内,可能会因为信用凭证的逾期,导致信用为负。因此银行在评估企业信用时,需要查询企业的所有交易信息。
融资
信用凭证的产生和转移都是一样的,只不过信用凭证的产生是从金融机构到企业,而转移是企业和企业间的转移。企业还可以向银行融资(借入人民币),操作不太一样,企业需要将自己的信用凭证转移给银行,银行向企业提供人民币贷款。到期时企业向银行还款,银行向企业返还信用凭证。
账户体系
本合约将用户分为以下几种
央行
合约的管理员账户(部署合约时传入)由央行控制,允许央行审核、管理金融机构和政府的账号。审核机制允许央行审查账户的真实性,避免账户被冒名顶替。
央行可以通过调用合约更新自己的信用凭证总量,和增发货币一样,该机制允许央行调节合约内的信用凭证总量,以便进行宏观调控。
央行可以通过合约向银行派发信用凭证,并设置有效期。这种方式类似央行的逆回购操作,是允许央行调节市场中信用凭证总量的另一个手段。通过审查金融机构的担保能力和信誉,央行可以借此机制精准调控每个金融机构能派发的信用凭证总量。避免金融机构过量担保,产生造成经济不稳定的因素。
央行具有合约数据库的管理权限,央行可以直接修改合约数据库,以便执行合约未提供的高级操作。通过 FISCO-BCOS 提供的 CRUD 合约来查询合约数据库的数据、对某个账号的交易进行管理。
政府
政府账户只负责审核企业。由于企业比较多,管理员一般没有足够精力管理这么多账户,因此开设新的一个层级来管理企业。政府可以审核企业资质,准许企业进入区块链,也可以剥夺企业的区块链账户。
政府账户也是一个普通的账户,可以接受和转移信用凭证,地方政府可以通过其区块链账户来进行融资操作。
金融机构
金融机构可以从央行获得信用凭证,代表央行对金融机构的信用评级,允许金融机构最多担保多少款项。金融机构若遇到企业希望融资,可以查询企业的相关信息:企业的借入借出凭证总额、企业的借入借出交易细表。以便金融机构结合企业的实际情况和区块链内的信用派生情况,对企业的再盈利能力进行评估。
金融机构在为企业融资时,可能需要再次验证企业的还款能力。金融机构可以查询区块链内所有企业的交易信息,因此金融机构可以沿信用凭证转移链查询到信用凭证来源,也就是查询到供应链上游企业是向哪个金融机构获取信用凭证的。通过认可供应链上游企业依赖的金融机构的信誉,这个金融机构便可以向该下游企业提供贷款。
企业
企业可以查询自己的借入借出凭证,允许向其他企业转移信用凭证,前提是双方都要确认交易。这样供应链下游企业就可以借助供应链上游企业的信誉,融到人民币。
本文转载自:http://www.biyezuopin.vip/onews.asp?id=16517
三、合约核心功能
合约事件
该合约会创建一些事件,以便其他合约能参与到信用凭证的转移中来,提升合约的可扩展性。
// 公司注册事件event CompanyRegistration(address addr, string name);// 银行注册事件event BankRegistration(address addr, string name);// 政府注册事件event GovernmentRegistration(address addr, string name);// 信用凭证交易发起事件event TransactionBegin(address debtor, address debtee, int receiptId, int256 amount);// 信用凭证交易接受事件event TransactionEnd(address debtor, address debtee, int receiptId);// 信用凭证销毁发起事件event ReturnBegin(address debtor, address debtee, int receiptId, int amount);// 信用凭证销毁接受事件event ReturnEnd(address debtor, address debtee, int receiptId, int amount);金融机构和政府机构注册根据设计,金融机构注册需要央行确认。通过在管理控制台注册时,管理控制台会提交注册信息给央行账户,央行账户确认后将注册信息提交到区块链上。政府机构账号同理。区块链合约注册函数的代码如下:// 央行将指定账户设置为金融机构,信用额度function registerBank(address addr, string name) public {require(msg.sender == adminAddr, "Only the Central Bank is allowed to banks registration");insertCompany(addr, name, true, false, 0, 0);emit BankRegistration(addr, name);}// 政府账号调用本函数将账户注册为公司// 每个账号只能注册一次function registerGovernment(address addr, string name) public {require(msg.sender == adminAddr, "Only the Central Bank is allowed to governments registration");insertCompany(addr, name, false, true, 0, 0);emit GovernmentRegistration(addr, name);}区块链合约保证只有央行账户可以调用该合约,将指定的金融机构账户设置为金融机构。企业注册企业注册和其他不同,企业注册需要政府审核,因此检查 msg.sender 是否是政府而不是央行。和银行注册类似,企业在管理控制台注册时,需要提供政府账号,将注册信息提交给政府审核。// 政府账号调用本函数将账户注册为公司// 每个账号只能注册一次function registerCompany(address addr, string name) public {findCompany(msg.sender);require(company.gov, "Only governments are allowed to companies registration");insertCompany(addr, name, false, false, 0, 0);emit CompanyRegistration(addr, name);}转账转账分为提交转账和确认转账两个步骤。合约首先将转账提交到数据库中记录,允许债权人确认接受转账和拒绝转账。转账为等待接受、接受、拒绝的状态将被记录到数据库中。被拒绝的转账记录会保留。其中,提交转账不会改变双方的账款,只有债权方接受了转账后才会改变双方的账款。// 由第三方金融机构账户调用本函数,表示 debtor 公司向 debtee 公司转移信用凭证,// 或者 debtor 公司向 debtee 银行借款(将 debtor 的信用转移给银行表示融资)// 或者 debtor 银行向 debtee 公司提供信用凭证// debtor=msg.senderfunction transferCredit(address debtee, int amount, int deadline) public {require(amount > 0, "You must transfer credits non negative");int debtorIn; int debtorOut; (debtorIn, debtorOut) = findCompanyBalance(msg.sender); // 债务人int debteeIn; int debteeOut; (debteeIn, debteeOut) = findCompanyBalance(debtee); // 债权人require(debtorIn - debtorOut >= amount, "Debtor does not have enough balance");nextReceiptId++;insertReceipt("t_in_receipt", toString(debtee), msg.sender, debtee, nextReceiptId, amount, deadline, 0);insertReceipt("t_out_receipt", toString(msg.sender), msg.sender, debtee, nextReceiptId, amount, deadline, 0);emit TransactionBegin(msg.sender, debtee, nextReceiptId, amount);}// 由债权人调用,表示接受债务人转移的信用凭证// valid = 1 表示接受转移,valid = 2 表示拒绝转移function acceptTransferCredit(int receiptId, int valid) public {require(valid == 1 || valid == 2, "Only accepting or declining are allowed");findReceipt("t_in_receipt", toString(msg.sender), receiptId);require(receipt.valid == 0, "Receipt to be accepted should be pending");if (valid == 1) {int debtorIn; int debtorOut; (debtorIn, debtorOut) = findCompanyBalance(msg.sender); // 债务人int debteeIn; int debteeOut; (debteeIn, debteeOut) = findCompanyBalance(debtee); // 债权人debtorOut += receipt.amount;debteeIn += receipt.amount;updateCompanyBalance(msg.sender, debtorIn, debtorOut);updateCompanyBalance(debtee, debteeIn, debteeOut);}updateReceiptInt("t_in_receipt", toString(receipt.debtee), receiptId, "valid", valid, false);updateReceiptInt("t_out_receipt", toString(receipt.debtor), receiptId, "valid", valid, false);emit TransactionEnd(receipt.debtor, receipt.debtee, receiptId);}还款还款分为提交还款和确认还款两个步骤。合约首先将还款提交到数据库中记录(通过更新转账数据库实现),允许债务人确认接受还款和拒绝还款。还款为等待接受、接受、拒绝的状态将被记录到数据库中。被拒绝的还款记录不像被拒绝的转账记录,不会被保留。和转账一样,还款未被确认前不会改变双方的账款,只有债务方接受了还款后才会改变双方的账款。// 由债权人调用,表示返还信用凭证// debtee 公司向 debtor 公司返还信用凭证(表示 debtor 公司向 debtee 公司支付货款)// debtee 公司向 debtor 银行返还信用凭证(表示期限前撤销信用凭证)// debtee 银行向 debtor 公司返还信用凭证(公司完成融资还款)function returnCredit(int receiptId, int amount) public {findReceipt("t_in_receipt", toString(msg.sender), receiptId);int debtorIn; int debtorOut; (debtorIn, debtorOut) = findCompanyBalance(receipt.debtor); // 债务人int debteeIn; int debteeOut; (debteeIn, debteeOut) = findCompanyBalance(receipt.debtee); // 债权人require(amount > 0, "You must return credits non negative");require(receipt.amount >= amount, "Cannot return credit more than amount transfered at first");require(receipt.valid == 1, "Receipt should be already accepted");updateReceiptInt("t_in_receipt", toString(receipt.debtee), receiptId, "valid", 3, false);updateReceiptInt("t_out_receipt", toString(receipt.debtor), receiptId, "valid", 3, false);// 只更新一方的账款,用两侧账款差表示还款总额updateReceiptInt("t_out_receipt", toString(receipt.debtor), receiptId, "amount", receipt.amount - amount, false);emit ReturnBegin(receipt.debtor, receipt.debtee, receiptId, amount);}// 由债务人调用,表示接受债权人返还的信用凭证function acceptReturnCredit(int receiptId, int valid) public {require(valid == 1 || valid == 2, "Only accepting or declining are allowed");findReceipt("t_out_receipt", toString(msg.sender), receiptId);Receipt memory outReceipt = receipt;findReceipt("t_in_receipt", toString(receipt.debtee), receiptId);Receipt memory inReceipt = receipt;require(inReceipt.valid == outReceipt.valid, "Receipt states are nonconsistent");require(inReceipt.valid == 3, "Only Receipts pending for returning are allowed to accept");require(outReceipt.amount < inReceipt.amount, "Receipts states are nonconsistent");int debtorIn; int debtorOut; (debtorIn, debtorOut) = findCompanyBalance(receipt.debtor); // 债务人int debteeIn; int debteeOut; (debteeIn, debteeOut) = findCompanyBalance(receipt.debtee); // 债权人int amount = inReceipt.amount - outReceipt.amount;if (valid == 1) { // 接受返还信用凭证// 同步两侧账款updateReceiptInt("t_in_receipt", toString(receipt.debtee), receiptId, "amount", outReceipt.amount, true);updateReceiptInt("t_out_receipt", toString(receipt.debtor), receiptId, "amount", outReceipt.amount, true);debtorOut -= amount;debteeIn -= amount;updateCompanyBalance(receipt.debtor, debtorIn, debtorOut);updateCompanyBalance(receipt.debtee, debteeIn, debteeOut);} else { // 拒绝返还信用凭证,恢复账款// 恢复单侧账款updateReceiptInt("t_out_receipt", toString(receipt.debtor), receiptId, "amount", inReceipt.amount, true);}// 恢复账款到接受状态updateReceiptInt("t_in_receipt", toString(receipt.debtee), receiptId, "valid", 1, false);updateReceiptInt("t_out_receipt", toString(receipt.debtor), receiptId, "valid", 1, false);emit ReturnEnd(receipt.debtor, receipt.debtee, receiptId, amount);}