PCEtLXtzdWJ0ZW1wbGF0ZSBjb21tb24vaGVhZGVyX2NvbW1vbn0tLT4JPCEtLXtpZiAkX0dFVFsnbW9kJ10gPT0gJ3ZpZXd0aHJlYWQnICYmICFlbXB0eSgkX0dbJ3RpZCddKX0tLT4KCTxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy5xaWRhbzEyMy5jb20vYmJzL3RocmVhZC17JF9HWyd0aWQnXX0tMS0xLmh0bWwiIC8+Cgk8IS0te2Vsc2VpZiAkX0dFVFsnbW9kJ10gPT0gJ2ZvcnVtZGlzcGxheScgJiYgIWVtcHR5KCRfR1snZmlkJ10pfS0tPgoJPGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vd3d3LnFpZGFvMTIzLmNvbS9iYnMvZm9ydW0teyRfR1snZmlkJ119LTEuaHRtbCIgLz4KCTwhLS17ZWxzZWlmICRfR0VUWydtb2QnXSA9PSAnZ3VpZGUnfS0tPgoJPGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vd3d3LnFpZGFvMTIzLmNvbS9iYnMvZ3VpZGUvIiAvPgoJPCEtLXtlbHNlaWYgJF9HWydiYXNlc2NyaXB0J10gPT0gJ2ZvcnVtJyAmJiAoZW1wdHkoJF9HRVRbJ21vZCddKSB8fCAkX0dFVFsnbW9kJ10gPT0gJ2luZGV4Jyl9LS0+Cgk8bGluayByZWw9ImNhbm9uaWNhbCIgaHJlZj0iaHR0cHM6Ly93d3cucWlkYW8xMjMuY29tL2Jicy8iIC8+Cgk8IS0tey9pZn0tLT4KCXJgbmB0PG1ldGEgbmFtZT0iYXBwbGljYXRpb24tbmFtZSIgY29udGVudD0iJF9HWydzZXR0aW5nJ11bJ2JibmFtZSddIiAvPgoJPG1ldGEgbmFtZT0ibXNhcHBsaWNhdGlvbi10b29sdGlwIiBjb250ZW50PSIkX0dbJ3NldHRpbmcnXVsnYmJuYW1lJ10iIC8+Cgk8IS0te2lmICRfR1snc2V0dGluZyddWydwb3J0YWxzdGF0dXMnXX0tLT48bWV0YSBuYW1lPSJtc2FwcGxpY2F0aW9uLXRhc2siIGNvbnRlbnQ9Im5hbWU9JF9HWydzZXR0aW5nJ11bJ25hdnMnXVsxXVsnbmF2bmFtZSddO2FjdGlvbi11cmk9e2VjaG8gIWVtcHR5KCRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ3BvcnRhbCddKSA/ICRfR1snc2NoZW1lJ10uJzovLycuJF9HWydzZXR0aW5nJ11bJ2RvbWFpbiddWydhcHAnXVsncG9ydGFsJ10gOiAkX0dbc2l0ZXVybF0uJ3BvcnRhbC5waHAnfTtpY29uLXVyaT17JF9HW3NpdGV1cmxdfXtJTUdESVJ9L3BvcnRhbC5pY28iIC8+PCEtLXsvaWZ9LS0+Cgk8bWV0YSBuYW1lPSJtc2FwcGxpY2F0aW9uLXRhc2siIGNvbnRlbnQ9Im5hbWU9JF9HWydzZXR0aW5nJ11bJ25hdnMnXVsyXVsnbmF2bmFtZSddO2FjdGlvbi11cmk9e2VjaG8gIWVtcHR5KCRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2ZvcnVtJ10pID8gJF9HWydzY2hlbWUnXS4nOi8vJy4kX0dbJ3NldHRpbmcnXVsnZG9tYWluJ11bJ2FwcCddWydmb3J1bSddIDogJF9HW3NpdGV1cmxdLidmb3J1bS5waHAnfTtpY29uLXVyaT17JF9HW3NpdGV1cmxdfXtJTUdESVJ9L2Jicy5pY28iIC8+Cgk8IS0te2lmICRfR1snc2V0dGluZyddWydncm91cHN0YXR1cyddfS0tPjxtZXRhIG5hbWU9Im1zYXBwbGljYXRpb24tdGFzayIgY29udGVudD0ibmFtZT0kX0dbJ3NldHRpbmcnXVsnbmF2cyddWzNdWyduYXZuYW1lJ107YWN0aW9uLXVyaT17ZWNobyAhZW1wdHkoJF9HWydzZXR0aW5nJ11bJ2RvbWFpbiddWydhcHAnXVsnZ3JvdXAnXSkgPyAkX0dbJ3NjaGVtZSddLic6Ly8nLiRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2dyb3VwJ10gOiAkX0dbc2l0ZXVybF0uJ2dyb3VwLnBocCd9O2ljb24tdXJpPXskX0dbc2l0ZXVybF19e0lNR0RJUn0vZ3JvdXAuaWNvIiAvPjwhLS17L2lmfS0tPgoJPCEtLXtpZiBoZWxwZXJfYWNjZXNzOjpjaGVja19tb2R1bGUoJ2ZlZWQnKX0tLT48bWV0YSBuYW1lPSJtc2FwcGxpY2F0aW9uLXRhc2siIGNvbnRlbnQ9Im5hbWU9JF9HWydzZXR0aW5nJ11bJ25hdnMnXVs0XVsnbmF2bmFtZSddO2FjdGlvbi11cmk9e2VjaG8gIWVtcHR5KCRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2hvbWUnXSkgPyAkX0dbJ3NjaGVtZSddLic6Ly8nLiRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2hvbWUnXSA6ICRfR1tzaXRldXJsXS4naG9tZS5waHAnfTtpY29uLXVyaT17JF9HW3NpdGV1cmxdfXtJTUdESVJ9L2hvbWUuaWNvIiAvPjwhLS17L2lmfS0tPgoJPCEtLXtpZiAkX0dbJ2Jhc2VzY3JpcHQnXSA9PSAnZm9ydW0nICYmICRfR1snc2V0dGluZyddWydhcmNoaXZlciddfS0tPgoJCTxsaW5rIHJlbD0iYXJjaGl2ZXMiIHRpdGxlPSIkX0dbJ3NldHRpbmcnXVsnYmJuYW1lJ10iIGhyZWY9InskX0dbc2l0ZXVybF19YXJjaGl2ZXIvIiAvPgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmICFlbXB0eSgkcnNzaGVhZCl9LS0+JHJzc2hlYWQ8IS0tey9pZn0tLT4KCTwhLS17aWYgd2lkdGhhdXRvKCl9LS0+CgkJPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBpZD0iY3NzX3dpZHRoYXV0byIgdHlwZT0idGV4dC9jc3MiIGhyZWY9J3skX0dbJ3NldHRpbmcnXVsnY3NzcGF0aCddfXtTVFlMRUlEfV93aWR0aGF1dG8uY3NzP3tWRVJIQVNIfScgLz4KCQk8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+SFRNTE5PREUuY2xhc3NOYW1lICs9ICcgd2lkdGhhdXRvJzwvc2NyaXB0PgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmICRfR1snYmFzZXNjcmlwdCddID09ICdmb3J1bScgfHwgJF9HWydiYXNlc2NyaXB0J10gPT0gJ2dyb3VwJ30tLT4KCQk8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJ7JF9HW3NldHRpbmddW2pzcGF0aF19Zm9ydW0uanM/e1ZFUkhBU0h9Ij48L3NjcmlwdD4KCTwhLS17ZWxzZWlmICRfR1snYmFzZXNjcmlwdCddID09ICdob21lJ30tLT4KCQk8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJ7JF9HW3NldHRpbmddW2pzcGF0aF19aG9tZS5qcz97VkVSSEFTSH0iPjwvc2NyaXB0PgoJPCEtLXtlbHNlaWYgJF9HWydiYXNlc2NyaXB0J10gPT0gJ3BvcnRhbCd9LS0+CgkJPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIHNyYz0ieyRfR1tzZXR0aW5nXVtqc3BhdGhdfXBvcnRhbC5qcz97VkVSSEFTSH0iPjwvc2NyaXB0PgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmICRfR1snYmFzZXNjcmlwdCddICE9ICdwb3J0YWwnICYmICRfR0VUWydkaXknXSA9PSAneWVzJyAmJiBjaGVja19kaXlfcGVybSgkdG9waWMpfS0tPgoJCTxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9InskX0dbc2V0dGluZ11banNwYXRoXX1wb3J0YWwuanM/e1ZFUkhBU0h9Ij48L3NjcmlwdD4KCTwhLS17L2lmfS0tPgoJPCEtLXtpZiAkX0dFVFsnZGl5J10gPT0gJ3llcycgJiYgY2hlY2tfZGl5X3Blcm0oJHRvcGljKX0tLT4KCQk8bGluayByZWw9InN0eWxlc2hlZXQiIHR5cGU9InRleHQvY3NzIiBpZD0iZGl5X2NvbW1vbiIgaHJlZj0ieyRfR1snc2V0dGluZyddWydjc3NwYXRoJ119e1NUWUxFSUR9X2Nzc19kaXkuY3NzP3tWRVJIQVNIfSIgLz4KCTwhLS17L2lmfS0tPgo8L2hlYWQ+Cgo8Ym9keSBpZD0ibnZfeyRfR1tiYXNlc2NyaXB0XX0iIGNsYXNzPSJwZ197Q1VSTU9EVUxFfXtpZiAkX0dbJ2Jhc2VzY3JpcHQnXSA9PT0gJ3BvcnRhbCcgJiYgQ1VSTU9EVUxFID09PSAnbGlzdCcgJiYgIWVtcHR5KCRjYXQpfSB7JGNhdFsnYm9keWNzcyddfXsvaWZ9IiBvbmtleWRvd249ImlmKGV2ZW50LmtleUNvZGU9PTI3KSByZXR1cm4gZmFsc2U7Ij4KCTxkaXYgaWQ9ImFwcGVuZF9wYXJlbnQiPjwvZGl2PjxkaXYgaWQ9ImFqYXh3YWl0aWQiPjwvZGl2PgoJPCEtLXtpZiAkX0dFVFsnZGl5J10gPT0gJ3llcycgJiYgY2hlY2tfZGl5X3Blcm0oJHRvcGljKX0tLT4KCQk8IS0te3RlbXBsYXRlIGNvbW1vbi9oZWFkZXJfZGl5fS0tPgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmIGNoZWNrX2RpeV9wZXJtKCR0b3BpYyl9LS0+CgkJPCEtLXt0ZW1wbGF0ZSBjb21tb24vaGVhZGVyX2RpeW5hdn0tLT4KCTwhLS17L2lmfS0tPgoJPCEtLXtpZiBDVVJNT0RVTEUgPT0gJ3RvcGljJyAmJiAkdG9waWMgJiYgZW1wdHkoJHRvcGljWyd1c2VoZWFkZXInXSkgJiYgY2hlY2tfZGl5X3Blcm0oJHRvcGljKX0tLT4KCQkkZGl5bmF2Cgk8IS0tey9pZn0tLT4KCTwhLS17aWYgZW1wdHkoJHRvcGljKSB8fCAkdG9waWNbJ3VzZWhlYWRlciddfS0tPgoJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ21vYmlsZSddWydhbGxvd21vYmlsZSddICYmICghJF9HWydzZXR0aW5nJ11bJ2NhY2hlaW5kZXhsaWZlJ10gJiYgISRfR1snc2V0dGluZyddWydjYWNoZXRocmVhZG9uJ10gfHwgJF9HWyd1aWQnXSkgJiYgKCRfR0VUWydkaXknXSAhPSAneWVzJyB8fCAhJF9HRVRbJ2luYWpheCddKSAmJiAoJF9HWydtb2JpbGUnXSAhPSAnJyAmJiAkX0dbJ2Nvb2tpZSddWydtb2JpbGUnXSA9PSAnJyAmJiAkX0dFVFsnbW9iaWxlJ10gIT0gJ25vJyl9LS0+CgkJCTxkaXYgY2xhc3M9InhpMSBibSBibV9jIj4KCQkJICAgIHtsYW5nIHlvdXJfbW9iaWxlX2Jyb3dzZXJ9PGEgaHJlZj0ieyRfR1snc2l0ZXVybCddfWZvcnVtLnBocD9tb2JpbGU9eWVzIj57bGFuZyBnb190b19tb2JpbGV9PC9hPiA8c3BhbiBjbGFzcz0ieGcxIj58PC9zcGFuPiA8YSBocmVmPSIkX0dbJ3NldHRpbmcnXVsnbW9iaWxlJ11bJ25vbW9iaWxldXJsJ10iPntsYW5nIHRvX2JlX2NvbnRpbnVlfTwvYT4KCQkJPC9kaXY+CgkJPCEtLXsvaWZ9LS0+CgkJPCEtLXtpZiAhZW1wdHkoJF9HWydzZXR0aW5nJ11bJ3Nob3J0Y3V0J10pICYmICRfR1snbWVtYmVyJ11bY3JlZGl0c10gPj0gJF9HWydzZXR0aW5nJ11bJ3Nob3J0Y3V0J119LS0+CgkJCTxkaXYgaWQ9InNob3J0Y3V0Ij4KCQkJCTxzcGFuPjxhIGhyZWY9ImphdmFzY3JpcHQ6OyIgaWQ9InNob3J0Y3V0Y2xvc2VpZCIgdGl0bGU9IntsYW5nIGNsb3NlfSI+e2xhbmcgY2xvc2V9PC9hPjwvc3Bhbj4KCQkJCXtsYW5nIHNob3J0Y3V0X25vdGljZX0KCQkJCTxhIGhyZWY9ImphdmFzY3JpcHQ6OyIgaWQ9InNob3J0Y3V0dGlwIj57bGFuZyBzaG9ydGN1dF9hZGR9PC9hPgoKCQkJPC9kaXY+CgkJCTxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij5zZXRUaW1lb3V0KHNldFNob3J0Y3V0LCAyMDAwKTs8L3NjcmlwdD4KCQk8IS0tey9pZn0tLT4KCQk8ZGl2IGlkPSJ0b3B0YiIgY2xhc3M9ImNsIj4KCQkJPCEtLXtob29rL2dsb2JhbF9jcG5hdl90b3B9LS0+CgkJCTxkaXYgY2xhc3M9IndwIj4KCQkJCTxkaXYgY2xhc3M9InoiPgoJCQkJCTwhLS17bG9vcCAkX0dbJ3NldHRpbmcnXVsndG9wbmF2cyddWzBdICRuYXZ9LS0+CgkJCQkJCTwhLS17aWYgaXNfYXJyYXkoJG5hdikgJiYgJG5hdlsnYXZhaWxhYmxlJ10gJiYgKCEkbmF2WydsZXZlbCddIHx8ICgkbmF2WydsZXZlbCddID09IDEgJiYgJF9HWyd1aWQnXSkgfHwgKCRuYXZbJ2xldmVsJ10gPT0gMiAmJiAkX0dbJ2FkbWluaWQnXSA+IDApIHx8ICgkbmF2WydsZXZlbCddID09IDMgJiYgJF9HWydhZG1pbmlkJ10gPT0gMSkpfS0tPiRuYXZbY29kZV08IS0tey9pZn0tLT4KCQkJCQk8IS0tey9sb29wfS0tPgoJCQkJCTwhLS17aG9vay9nbG9iYWxfY3BuYXZfZXh0cmExfS0tPgoJCQkJPC9kaXY+CgkJCQk8ZGl2IGNsYXNzPSJ5Ij4KCQkJCQk8YSBpZD0ic3dpdGNoYmxpbmQiIGhyZWY9ImphdmFzY3JpcHQ6OyIgb25jbGljaz0idG9nZ2xlQmxpbmQodGhpcykiIHRpdGxlPSJ7bGFuZyBzd2l0Y2hfYmxpbmR9IiBjbGFzcz0ic3dpdGNoYmxpbmQiPjwvYT4KCQkJCQk8IS0te2hvb2svZ2xvYmFsX2NwbmF2X2V4dHJhMn0tLT4KCQkJCQk8IS0te2xvb3AgJF9HWydzZXR0aW5nJ11bJ3RvcG5hdnMnXVsxXSAkbmF2fS0tPgoJCQkJCQk8IS0te2lmIGlzX2FycmF5KCRuYXYpICYmICRuYXZbJ2F2YWlsYWJsZSddICYmICghJG5hdlsnbGV2ZWwnXSB8fCAoJG5hdlsnbGV2ZWwnXSA9PSAxICYmICRfR1sndWlkJ10pIHx8ICgkbmF2WydsZXZlbCddID09IDIgJiYgJF9HWydhZG1pbmlkJ10gPiAwKSB8fCAoJG5hdlsnbGV2ZWwnXSA9PSAzICYmICRfR1snYWRtaW5pZCddID09IDEpKX0tLT4kbmF2W2NvZGVdPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXsvbG9vcH0tLT4KCQkJCQk8IS0te2lmIGVtcHR5KCRfR1snZGlzYWJsZWR3aWR0aGF1dG8nXSkgJiYgJF9HWydzZXR0aW5nJ11bJ3N3aXRjaHdpZHRoYXV0byddfS0tPgoJCQkJCQk8YSBocmVmPSJqYXZhc2NyaXB0OjsiIGlkPSJzd2l0Y2h3aWR0aCIgb25jbGljaz0id2lkdGhhdXRvKHRoaXMpIiB0aXRsZT0ie2lmIHdpZHRoYXV0bygpfXtsYW5nIHN3aXRjaF9uYXJyb3d9e2Vsc2V9e2xhbmcgc3dpdGNoX3dpZGV9ey9pZn0iIGNsYXNzPSJzd2l0Y2h3aWR0aCI+PCEtLXtpZiB3aWR0aGF1dG8oKX0tLT57bGFuZyBzd2l0Y2hfbmFycm93fTwhLS17ZWxzZX0tLT57bGFuZyBzd2l0Y2hfd2lkZX08IS0tey9pZn0tLT48L2E+CgkJCQkJPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXtpZiAkX0dbJ3VpZCddICYmICFlbXB0eSgkX0dbJ3N0eWxlJ11bJ2V4dHN0eWxlJ10pfS0tPjxhIGlkPSJzc2xjdCIgaHJlZj0iamF2YXNjcmlwdDo7IiBvbm1vdXNlb3Zlcj0iZGVsYXlTaG93KHRoaXMsIGZ1bmN0aW9uKCkge3Nob3dNZW51KHsnY3RybGlkJzonc3NsY3QnLCdwb3MnOiczNCEnfSl9KTsiPntsYW5nIGNoYW5nZXN0eWxlfTwvYT48IS0tey9pZn0tLT4KCQkJCQk8IS0te2lmIGNoZWNrX2RpeV9wZXJtKCR0b3BpYyl9LS0+CgkJCQkJCSRkaXluYXYKCQkJCQk8IS0tey9pZn0tLT4KCQkJCTwvZGl2PgoJCQk8L2Rpdj4KCQk8L2Rpdj4KCgkJPCEtLXtpZiAhSVNfUk9CT1R9LS0+CgkJCTwhLS17aWYgJF9HWyd1aWQnXSAmJiAhJF9HWydzZXR0aW5nJ11bJ2JiY2xvc2VkJ10gJiYgZW1wdHkoJF9HWydtZW1iZXInXVsnZnJlZXplJ10pICYmICRfR1snbWVtYmVyJ11bJ2dyb3VwaWQnXSAhPSA1fS0tPgoJCQk8dWwgaWQ9Im15cHJvbXB0X21lbnUiIGNsYXNzPSJwX3BvcCIgc3R5bGU9ImRpc3BsYXk6IG5vbmU7Ij4KCQkJCTxsaT48YSBocmVmPSJob21lLnBocD9tb2Q9c3BhY2UmZG89cG0iIGlkPSJwbV9udGMiIHN0eWxlPSJiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0OyBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAwIDUwJTsiPjxlbSBjbGFzcz0icHJvbXB0X25ld3N7aWYgZW1wdHkoJF9HW21lbWJlcl1bbmV3cG1dKX1fMHsvaWZ9Ij48L2VtPntsYW5nIHBtX2NlbnRlcn08L2E+PC9saT4KCQkJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ2ZvbGxvd3N0YXR1cyddfS0tPgoJCQkJCTxsaT48YSBocmVmPSJob21lLnBocD9tb2Q9Zm9sbG93JmRvPWZvbGxvd2VyIj48ZW0gY2xhc3M9InByb21wdF9mb2xsb3dlcntpZiBlbXB0eSgkX0dbbWVtYmVyXVtuZXdwcm9tcHRfbnVtXVtmb2xsb3dlcl0pfV8wey9pZn0iPjwvZW0+PCEtLXtsYW5nIG5vdGljZV9pbnRlcmFjdGl2ZV9mb2xsb3dlcn0tLT57aWYgJF9HW21lbWJlcl1bbmV3cHJvbXB0X251bV1bZm9sbG93ZXJdfSgkX0dbbWVtYmVyXVtuZXdwcm9tcHRfbnVtXVtmb2xsb3dlcl0pey9pZn08L2E+PC9saT4KCQkJCQk8IS0te2lmICRfR1ttZW1iZXJdW25ld3Byb21wdF0gJiYgJF9HW21lbWJlcl1bbmV3cHJvbXB0X251bV1bZm9sbG93XX0tLT4KCQkJCQkJPGxpPjxhIGhyZWY9ImhvbWUucGhwP21vZD1mb2xsb3ciPjxlbSBjbGFzcz0icHJvbXB0X2NvbmNlcm4iPjwvZW0+PCEtLXtsYW5nIG5vdGljZV9pbnRlcmFjdGl2ZV9mb2xsb3d9LS0+KCRfR1ttZW1iZXJdW25ld3Byb21wdF9udW1dW2ZvbGxvd10pPC9hPjwvbGk+CgkJCQkJPCEtLXsvaWZ9LS0+CgkJCQk8IS0tey9pZn0tLT4KCQkJCTwhLS17aWYgJF9HW21lbWJlcl1bbmV3cHJvbXB0XX0tLT4KCQkJCQk8IS0te2xvb3AgJF9HWydtZW1iZXInXVsnY2F0ZWdvcnlfbnVtJ10gJGtleSAkdmFsfS0tPgoJCQkJCQk8bGk+PGEgaHJlZj0iaG9tZS5waHA/bW9kPXNwYWNlJmRvPW5vdGljZSZ2aWV3PSRrZXkiPjxlbSBjbGFzcz0ibm90aWNlXyRrZXkiPjwvZW0+PCEtLXtlY2hvIGxhbmcoJ3RlbXBsYXRlJywgJ25vdGljZV8nLiRrZXkpfS0tPig8c3BhbiBjbGFzcz0icnEiPiR2YWw8L3NwYW4+KTwvYT48L2xpPgoJCQkJCTwhLS17L2xvb3B9LS0+CgkJCQk8IS0tey9pZn0tLT4KCQkJCTwhLS17aWYgZW1wdHkoJF9HWydjb29raWUnXVsnaWdub3JlX25vdGljZSddKX0tLT4KCQkJCQk8bGkgY2xhc3M9Imlnbm9yZV9ub3RpY2VsaSI+PGEgaHJlZj0iamF2YXNjcmlwdDo7IiBvbmNsaWNrPSJzZXRjb29raWUoJ2lnbm9yZV9ub3RpY2UnLCAxKTtoaWRlTWVudSgnbXlwcm9tcHRfbWVudScpIiB0aXRsZT0ie2xhbmcgdGVtcG9yYXJpbHlfdG9fcmVtaW5kfSI+PGVtIGNsYXNzPSJpZ25vcmVfbm90aWNlIj48L2VtPjwvYT48L2xpPgoJCQkJPCEtLXsvaWZ9LS0+CgkJCTwvdWw+CgkJCTwhLS17L2lmfS0tPgoJCQk8IS0te2lmICRfR1sndWlkJ10gJiYgIWVtcHR5KCRfR1snc3R5bGUnXVsnZXh0c3R5bGUnXSl9LS0+CgkJCQk8ZGl2IGlkPSJzc2xjdF9tZW51IiBjbGFzcz0iY2wgcF9wb3AiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+CgkJCQkJPCEtLXtpZiAhJF9HW3N0eWxlXVtkZWZhdWx0ZXh0c3R5bGVdfS0tPjxzcGFuIGNsYXNzPSJzc2xjdF9idG4iIG9uY2xpY2s9ImV4dHN0eWxlKCcnKSIgdGl0bGU9IntsYW5nIGRlZmF1bHR9Ij48aT48L2k+PC9zcGFuPjwhLS17L2lmfS0tPgoJCQkJCTwhLS17bG9vcCAkX0dbJ3N0eWxlJ11bJ2V4dHN0eWxlJ10gJGV4dHN0eWxlfS0tPgoJCQkJCQk8c3BhbiBjbGFzcz0ic3NsY3RfYnRuIiBvbmNsaWNrPSJleHRzdHlsZSgnJGV4dHN0eWxlWzBdJykiIHRpdGxlPSIkZXh0c3R5bGVbMV0iPjxpIHN0eWxlPSdiYWNrZ3JvdW5kOiRleHRzdHlsZVsyXSc+PC9pPjwvc3Bhbj4KCQkJCQk8IS0tey9sb29wfS0tPgoJCQkJPC9kaXY+CgkJCTwhLS17L2lmfS0tPgoJCQk8IS0te2lmICRfR1sndWlkJ119LS0+CgkJCQk8dWwgaWQ9Im15aXRlbV9tZW51IiBjbGFzcz0icF9wb3AiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+CgkJCQkJPCEtLXtpZiAkX0dbJ3NldHRpbmcnXVsnZm9ydW1zdGF0dXMnXX0tLT48bGk+PGEgaHJlZj0iaG9tZS5waHA/bW9kPXNwYWNlJmRvPXRocmVhZCZ2aWV3PW1lIj57bGFuZyBteXBvc3R9PC9hPjwvbGk+PCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXtpZiAkX0dbJ3NldHRpbmcnXVsnZmF2b3JpdGVzdGF0dXMnXX0tLT48bGk+PGEgaHJlZj0iaG9tZS5waHA/bW9kPXNwYWNlJmRvPWZhdm9yaXRlJnZpZXc9bWUiPntsYW5nIGZhdm9yaXRlfTwvYT48L2xpPjwhLS17L2lmfS0tPgoJCQkJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ2ZyaWVuZHN0YXR1cyddfS0tPjxsaT48YSBocmVmPSJob21lLnBocD9tb2Q9c3BhY2UmZG89ZnJpZW5kIj57bGFuZyBmcmllbmRzfTwvYT48L2xpPjwhLS17L2lmfS0tPgoJCQkJCTwhLS17aG9vay9nbG9iYWxfbXlpdGVtX2V4dHJhfS0tPgoJCQkJPC91bD4KCQkJPCEtLXsvaWZ9LS0+CgkJCTwhLS17c3VidGVtcGxhdGUgY29tbW9uL2hlYWRlcl9xbWVudX0tLT4KCQk8IS0tey9pZn0tLT4KCgkJPCEtLXthZC9oZWFkZXJiYW5uZXIvd3AgYV9ofS0tPgoJCTxkaXYgaWQ9ImhkIj4KCQkJPGRpdiBjbGFzcz0id3AiPgoJCQkJPGRpdiBjbGFzcz0iaGRjIGNsIj4KCQkJCQk8IS0te2V2YWwgJG1uaWQgPSBnZXRjdXJyZW50bmF2KCk7fS0tPgoJCQkJCTxoMj48IS0te2lmICFpc3NldCgkX0dbJ3NldHRpbmcnXVsnbmF2bG9nb3MnXVskbW5pZF0pfS0tPjxhIGhyZWY9IntpZiAkX0dbJ3NldHRpbmcnXVsnZG9tYWluJ11bJ2FwcCddWydkZWZhdWx0J119eyRfR1snc2NoZW1lJ119Oi8veyRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2RlZmF1bHQnXX0ve2Vsc2V9Li97L2lmfSIgdGl0bGU9IiRfR1snc2V0dGluZyddWydiYm5hbWUnXSI+eyRfR1snc3R5bGUnXVsnYm9hcmRsb2dvJ119PC9hPjwhLS17ZWxzZX0tLT4kX0dbJ3NldHRpbmcnXVsnbmF2bG9nb3MnXVskbW5pZF08IS0tey9pZn0tLT48L2gyPgoJCQkJCTwhLS17dGVtcGxhdGUgY29tbW9uL2hlYWRlcl91c2Vyc3RhdHVzfS0tPgoJCQkJPC9kaXY+CgoJCQkJPGRpdiBpZD0ibnYiPgoJCQkJCTxhIGhyZWY9ImphdmFzY3JpcHQ6OyIgaWQ9InFtZW51IiBvbm1vdXNlb3Zlcj0iZGVsYXlTaG93KHRoaXMsIGZ1bmN0aW9uICgpIHtzaG93TWVudSh7J2N0cmxpZCc6J3FtZW51JywncG9zJzonMzQhJywnY3RybGNsYXNzJzonYScsJ2R1cmF0aW9uJzoyfSk7c2hvd0ZvcnVtbWVudSgkX0dbZmlkXSk7fSkiPntsYW5nIG15X25hdn08L2E+CgkJCQkJPHVsPgoJCQkJCQk8IS0te2xvb3AgJF9HWydzZXR0aW5nJ11bJ25hdnMnXSAkbmF2fS0tPgoJCQkJCQkJPCEtLXtpZiBpc19hcnJheSgkbmF2KSAmJiAkbmF2WydhdmFpbGFibGUnXSAmJiAoISRuYXZbJ2xldmVsJ10gfHwgKCRuYXZbJ2xldmVsJ10gPT0gMSAmJiAkX0dbJ3VpZCddKSB8fCAoJG5hdlsnbGV2ZWwnXSA9PSAyICYmICRfR1snYWRtaW5pZCddID4gMCkgfHwgKCRuYXZbJ2xldmVsJ10gPT0gMyAmJiAkX0dbJ2FkbWluaWQnXSA9PSAxKSl9LS0+PGxpIHtpZiAkbW5pZCA9PSAkbmF2W25hdmlkXSB8fCBzdWJzdHIoJF9TRVJWRVJbJ1JFUVVFU1RfVVJJJ10sIDEpID09IHN0cl9yZXBsYWNlKCcuLycsICcnLCAkbmF2W2ZpbGVuYW1lXSl9Y2xhc3M9ImEiIHsvaWZ9JG5hdltuYXZdPjwvbGk+PCEtLXsvaWZ9LS0+CgkJCQkJCTwhLS17L2xvb3B9LS0+CgkJCQkJPC91bD4KCQkJCQk8IS0te2hvb2svZ2xvYmFsX25hdl9leHRyYX0tLT4KCQkJCTwvZGl2PgoJCQkJPCEtLXtpZiAhZW1wdHkoJF9HWydzZXR0aW5nJ11bJ3BsdWdpbnMnXVsnanNtZW51J10pfS0tPgoJCQkJCTx1bCBjbGFzcz0icF9wb3AgaF9wb3AiIGlkPSJwbHVnaW5fbWVudSIgc3R5bGU9ImRpc3BsYXk6IG5vbmUiPgoJCQkJCTwhLS17bG9vcCAkX0dbJ3NldHRpbmcnXVsncGx1Z2lucyddWydqc21lbnUnXSAkbW9kdWxlfS0tPgoJCQkJCQkgPCEtLXtpZiBpbl9hcnJheSgkbW9kdWxlWydhZG1pbmlkJ10sIGFycmF5KDAsIC0xKSkgfHwgKCRtb2R1bGVbJ2FkbWluaWQnXSAmJiAkX0dbJ2FkbWluaWQnXSA+IDAgJiYgJG1vZHVsZVsnYWRtaW5pZCddID49ICRfR1snYWRtaW5pZCddKX0tLT4KCQkJCQkJIDxsaT4kbW9kdWxlW3VybF08L2xpPgoJCQkJCQkgPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXsvbG9vcH0tLT4KCQkJCQk8L3VsPgoJCQkJPCEtLXsvaWZ9LS0+CgkJCQkkX0dbc2V0dGluZ11bbWVudW5hdnNdCgkJCQk8ZGl2IGlkPSJtdSIgY2xhc3M9ImNsIj4KCQkJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ3N1Ym5hdnMnXX0tLT4KCQkJCQk8IS0te2xvb3AgJF9HW3NldHRpbmddW3N1Ym5hdnNdICRuYXZpZCAkc3VibmF2fS0tPgoJCQkJCQk8IS0te2lmICRfR1snc2V0dGluZyddWyduYXZzdWJob3ZlciddIHx8ICRtbmlkID09ICRuYXZpZH0tLT4KCQkJCQkJPHVsIGNsYXNzPSJjbCB7aWYgJG1uaWQgPT0gJG5hdmlkfWN1cnJlbnR7L2lmfSIgaWQ9InNuYXZfJG5hdmlkIntpZiAkbW5pZCAhPSAkbmF2aWR9IHN0eWxlPSJkaXNwbGF5Om5vbmUiey9pZn0+CgkJCQkJCSRzdWJuYXYKCQkJCQkJPC91bD4KCQkJCQkJPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXsvbG9vcH0tLT4KCQkJCTwhLS17L2lmfS0tPgoJCQkJPC9kaXY+CgkJCQk8IS0te2FkL3N1Ym5hdmJhbm5lci9hX211fS0tPgoJCQkJPCEtLXtzdWJ0ZW1wbGF0ZSBjb21tb24vcHVic2VhcmNoZm9ybX0tLT4KCQkJPC9kaXY+CgkJPC9kaXY+CgoJCTwhLS17aG9vay9nbG9iYWxfaGVhZGVyfS0tPgoJPCEtLXsvaWZ9LS0+CgoJPGRpdiBpZD0id3AiIGNsYXNzPSJ3cCI+Cg==
qidao123.com ToB IT社区-企服评测·应用市场»论坛 › 区块链 › 区块链 › btc学习之交易原理及源码阅读一
返回列表 发新帖

btc学习之交易原理及源码阅读一

[复制链接]
发表于 2025-5-16 06:22:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
简介

比特币系统是一种点对点的电子现金系统,在这个系统中,最重要的概念就是交易了(这里的交易就等同于转账),当我们如今说起交易的时间,脑海中大概浮现很多关于block chian关于交易的很多原理以及概念,但为了理解btc最根本的概念及源码呢,我们可以先抛开所有已学过的一些知识,一步步去学习。
从最简单的开始,在我们实际生存中,我们发起一笔银行转账,你需要打开你的电子账户,在你的银行应用上输入接收款项的银行账户以及你需要转账多少钱。然后发起这笔交易。等待多少时间后,银行会通过某种方式通知你是到账了还是被原路返回了,就标志着这次交易的成功或者失败,这里的银行就是一个第三方中介,所有的交易都需要经过它。这里的前提是我们大家都信任这个银行,但是如今我们拿掉这个可以被信任的第三方中介呢,我们该如何做这个事情呢?
在我们的btc系统中,做到了这一点。它基于密码学原理而不基于信用,使得任何达成一致的双方,可以或许直接进行支付,从而不需要第三方中介的参与。但这里也会有引入一个新的问题,你无法确定发起交易的人是不是恶意的,他把同一笔钱同时转向多个人,那这时间大概又会想到引入一个中介,那就又回到了老路了,这里btc又提出了一个解决方案,它构建了如许的一个网络,该网络通过随机散列(hashing)对全部交易加上时间戳(timestamps),将它们合并入一个不断延伸的基于随机散列的工作量证明(proof-of-work)的链条作为交易纪录,除非重新完成全部的工作量证明,形成的交易纪录将不可更改。最长的链条不仅将作为被观察到的事件序列(sequence)的证明,而且被看做是来自CPU盘算能力最大的池(pool),只要大多数的CPU盘算能力都没有打算互助起来对全网进行攻击,那么诚实的节点将会生成最长的、凌驾攻击者的链条。这个系统自己需要的底子办法非常少。信息尽最大努力在全网流传即可,节点(nodes)可以随时离开和重新加入网络,并将最长的工作量证明链条作为在该节点离线期间发生的交易的证明。这段话是抄自比特币白皮书的一段原话,下面我们会根据比特币的文档,比特币白皮书,还有精通比特币这三份资料对中本聪版本的比特币代码做一个阅读了解他的详细实现。
源码阅读

源代码含注释

我们看下交易的结构体,包含n个输入与n个输出
  1. class CTransaction
  2. {
  3. public:
  4.     int nVersion;
  5.     vector<CTxIn> vin; //输入
  6.     vector<CTxOut> vout;//输出
  7.     int nLockTime;
  8.         ...
  9. }
复制代码
输入的类
  1. class CTxIn
  2. {
  3. public:
  4.     COutPoint prevout;// 包含了上一个交易的输出
  5.     CScript scriptSig; //解锁脚本
  6.     unsigned int nSequence;
  7.         ......
  8. }
  9. class COutPoint
  10. {
  11. public:
  12.     uint256 hash; //引用的前一个交易的id
  13.     unsigned int n;//输出的索引   使用的是上面hash对应的交易的第几个输出
  14.     ......
  15. }
复制代码
输出的结构
  1. class CTxOut
  2. {
  3. public:
  4.     int64 nValue;   //输出的金额
  5.     CScript scriptPubKey; //公钥脚本/锁定脚本
  6.     ......
  7. }
复制代码
光看代码大概有点不理解我在网上找了个图解释下

从图来理解代码(先抛开脚本部分),我们可以看出一个交易的输入/输出可以是多个,交易的输入对应前一个交易的输出。
理解了交易大体的结构之后我们看下代码中是如何发起交易的??
我们观察一下的代码,这段代码是发起了一笔转账,我们如今只需要先关注第一个if语句,他创建了一笔tx,返回一个bool,参数分别是对应的公钥脚本,发送的金额 , CWalletTx类型的一个引用,他是一个带有附加信息的交易结构体,最后一个参数是手续费。
  1. bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
  2. {
  3.     CRITICAL_BLOCK(cs_main)
  4.     {
  5.         int64 nFeeRequired;
  6.         if (!CreateTransaction(scriptPubKey, nValue, wtxNew, nFeeRequired))
  7.         {
  8.             string strError;
  9.             if (nValue + nFeeRequired > GetBalance())
  10.                 strError = strprintf("Error: This is an oversized transaction that requires a transaction fee of %s ", FormatMoney(nFeeRequired).c_str());
  11.             else
  12.                 strError = "Error: Transaction creation failed ";
  13.             wxMessageBox(strError, "Sending...");
  14.             return error("SendMoney() : %s\n", strError.c_str());
  15.         }
  16.         if (!CommitTransactionSpent(wtxNew))
  17.         {
  18.             wxMessageBox("Error finalizing transaction", "Sending...");
  19.             return error("SendMoney() : Error finalizing transaction");
  20.         }
  21.         printf("SendMoney: %s\n", wtxNew.GetHash().ToString().substr(0,6).c_str());
  22.         // Broadcast
  23.         if (!wtxNew.AcceptTransaction())
  24.         {
  25.             // This must not fail. The transaction has already been signed and recorded.
  26.             throw runtime_error("SendMoney() : wtxNew.AcceptTransaction() failed\n");
  27.             wxMessageBox("Error: Transaction not valid", "Sending...");
  28.             return error("SendMoney() : Error: Transaction not valid");
  29.         }
  30.         wtxNew.RelayWalletTransaction();
  31.     }
  32.     MainFrameRepaint();
  33.     return true;
  34. }
复制代码
让我们接下来观察下创建交易的函数方法,在这之前先观察以下聚集函数。
通过调用 SelectCoins 函数选择一组足够支付目标金额的输入交易。这组输入交易会被加入到 setCoins 聚会合。我们先来看下他的详细实现,通过for循环遍历自己未花费的金额,
  1. map<uint256, CWalletTx> mapWallet;  //utxo
  2. bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
  3. {
  4.     setCoinsRet.clear();
  5.     // List of values less than target
  6.     int64 nLowestLarger = _I64_MAX;
  7.     CWalletTx* pcoinLowestLarger = NULL;
  8.     vector<pair<int64, CWalletTx*> > vValue;
  9.     int64 nTotalLower = 0;  //累积小于目标金额的所有 UTXO 的总和
  10.     CRITICAL_BLOCK(cs_mapWallet)
  11.     {
  12.         //遍历 UTXO
  13.         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
  14.         {
  15.             CWalletTx* pcoin = &(*it).second;
  16.             if (!pcoin->IsFinal() || pcoin->fSpent)
  17.                 continue;
  18.             //获取这笔未花费的金额
  19.             int64 n = pcoin->GetCredit();
  20.             if (n <= 0)
  21.                 continue;
  22.             // 金额小于目标值的时候,先把它保存起来
  23.             if (n < nTargetValue)
  24.             {
  25.                 vValue.push_back(make_pair(n, pcoin));
  26.                 nTotalLower += n;  //累计金额
  27.             }
  28.             //如果找到正好等于目标金额的utxo项,直接获取之后返回
  29.             else if (n == nTargetValue)
  30.             {
  31.                 setCoinsRet.insert(pcoin);
  32.                 return true;
  33.             }
  34.             //大于目标金额 小于pcoinLowestLarger,在找不到就使用这一项
  35.             else if (n < nLowestLarger)
  36.             {
  37.                 nLowestLarger = n;
  38.                 pcoinLowestLarger = pcoin;
  39.             }
  40.         }
  41.     }
  42.     //挑选一个大于目标金额的最小的一个金额 返回回去使用
  43.     if (nTotalLower < nTargetValue)
  44.     {
  45.         if (pcoinLowestLarger == NULL)
  46.             return false;
  47.         setCoinsRet.insert(pcoinLowestLarger);
  48.         return true;
  49.     }
  50.     //下面的逻辑是通过组合各种子集找到最接近目标金额的最优解
  51.     // Solve subset sum by stochastic approximation
  52.     sort(vValue.rbegin(), vValue.rend());
  53.     vector<char> vfIncluded;
  54.     vector<char> vfBest(vValue.size(), true);
  55.     int64 nBest = nTotalLower;
  56.     for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
  57.     {
  58.         vfIncluded.assign(vValue.size(), false);
  59.         int64 nTotal = 0;
  60.         bool fReachedTarget = false;
  61.         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
  62.         {
  63.             for (int i = 0; i < vValue.size(); i++)
  64.             {
  65.                 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
  66.                 {
  67.                     nTotal += vValue[i].first;
  68.                     vfIncluded[i] = true;
  69.                     if (nTotal >= nTargetValue)
  70.                     {
  71.                         fReachedTarget = true;
  72.                         if (nTotal < nBest)
  73.                         {
  74.                             nBest = nTotal;
  75.                             vfBest = vfIncluded;
  76.                         }
  77.                         nTotal -= vValue[i].first;
  78.                         vfIncluded[i] = false;
  79.                     }
  80.                 }
  81.             }
  82.         }
  83.     }
  84.     // If the next larger is still closer, return it
  85.     if (pcoinLowestLarger && nLowestLarger - nTargetValue <= nBest - nTargetValue)
  86.         setCoinsRet.insert(pcoinLowestLarger);
  87.     else
  88.     {
  89.         for (int i = 0; i < vValue.size(); i++)
  90.             if (vfBest[i])
  91.                 setCoinsRet.insert(vValue[i].second);
  92.          debug print
  93.         printf("SelectCoins() best subset: ");
  94.         for (int i = 0; i < vValue.size(); i++)
  95.             if (vfBest[i])
  96.                 printf("%s ", FormatMoney(vValue[i].first).c_str());
  97.         printf("total %s\n", FormatMoney(nBest).c_str());
  98.     }
  99.     return true;
  100. }
  101. //IsFinal() 函数是用来判断交易是否已经“最终确定”(finalized),也就是说,交易是否可以被包含在区块链中
  102. bool IsFinal() const
  103. {
  104.         //nLockTime 是交易的一个字段,表示交易在某个时间点或区块高度之前不能被包含在区块中。
  105.     if (nLockTime == 0 || nLockTime < nBestHeight)
  106.         return true;
  107.    
  108.     // 遍历交易的每一个输入(vin 是交易输入的列表)
  109.     foreach(const CTxIn& txin, vin)
  110.         // 如果任何一个输入不是最终的,返回 false,表明交易不是最终的
  111.         if (!txin.IsFinal())
  112.             return false;
  113.     // 如果所有输入都是最终的,返回 true,表明交易是最终的
  114.     return true;
  115. }
复制代码
我们回到创建交易的地方,这里我有个地方一开始理解错了,在utxo中,保存到是跟用户钱包有关的未花费交易的完备信息,以是它包含了找零跟转账到另一个地点的输出,并不是我一开始想的utxo中就是单纯保存了只有我自己的关联的输出。以是每次使用的时间都需要去查抄这笔输出是否属于自己。下面代码简单的注释了下,但是有个地方需要留意AddSupportingTransactions,他是用来加载需要前置的一些交易
  1. map<uint256, CWalletTx> mapWallet;  //utxo
  2. ...省略
  3. bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, int64& nFeeRequiredRet)
  4. {
  5.     nFeeRequiredRet = 0;
  6.     CRITICAL_BLOCK(cs_main)
  7.     {
  8.         // txdb must be opened before the mapWallet lock
  9.         //只读的方式打开交易数据库
  10.         CTxDB txdb("r");
  11.         CRITICAL_BLOCK(cs_mapWallet)
  12.         {
  13.             int64 nFee = nTransactionFee;
  14.             loop
  15.             {
  16.                 wtxNew.vin.clear();
  17.                 wtxNew.vout.clear();
  18.                 if (nValue < 0)
  19.                     return false;
  20.                 int64 nValueOut = nValue;
  21.                 nValue += nFee;   //手续费+要发送的金额,得到总共需要多少资金
  22.                 // Choose coins to use
  23.                 set<CWalletTx*> setCoins;
  24.                 if (!SelectCoins(nValue, setCoins))
  25.                     return false;
  26.                 int64 nValueIn = 0;
  27.                 foreach(CWalletTx* pcoin, setCoins)
  28.                     nValueIn += pcoin->GetCredit();
  29.                 // 根据目标金额和手续费创建交易的输出 一个是目标收款方的输出
  30.                 // Fill vout[0] to the payee
  31.                 wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey));
  32.                 //找零的输出
  33.                 // Fill vout[1] back to self with any change
  34.                 if (nValueIn > nValue)
  35.                 {
  36.                     // Use the same key as one of the coins
  37.                     vector<unsigned char> vchPubKey;
  38.                     CTransaction& txFirst = *(*setCoins.begin());
  39.                     foreach(const CTxOut& txout, txFirst.vout)
  40.                         if (txout.IsMine())
  41.                             if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
  42.                                 break;
  43.                     if (vchPubKey.empty())
  44.                         return false;
  45.                     // Fill vout[1] to ourself
  46.                     CScript scriptPubKey;
  47.                     scriptPubKey << vchPubKey << OP_CHECKSIG;
  48.                     wtxNew.vout.push_back(CTxOut(nValueIn - nValue, scriptPubKey));
  49.                 }
  50.                 // 填充输入
  51.                 // Fill vin
  52.                 foreach(CWalletTx* pcoin, setCoins)
  53.                     for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
  54.                         if (pcoin->vout[nOut].IsMine())  
  55.                             wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));
  56.                 // Sign
  57.                 //签名
  58.                 int nIn = 0;
  59.                 foreach(CWalletTx* pcoin, setCoins)
  60.                     for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
  61.                         if (pcoin->vout[nOut].IsMine())
  62.                             SignSignature(*pcoin, wtxNew, nIn++);
  63.                 // Check that enough fee is included
  64.                 //计算交易费
  65.                 if (nFee < wtxNew.GetMinFee(true))
  66.                 {
  67.                     nFee = nFeeRequiredRet = wtxNew.GetMinFee(true);
  68.                     continue;
  69.                 }
  70.                 // Fill vtxPrev by copying from previous transactions vtxPrev
  71.                 //用于在创建新的交易时,确保交易的输入(即引用的 UTXO)所在的区块链分支已经被包括,并且能够追溯到最近的区块。
  72.                 // 这对于节点在验证交易时很重要,特别是在分叉链或者孤立链的情况下。
  73.                 wtxNew.AddSupportingTransactions(txdb);
  74.                 wtxNew.fTimeReceivedIsTxTime = true;
  75.                 break;
  76.             }
  77.         }
  78.     }
  79.     return true;
  80. }
  81. void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
  82. {
  83.     vtxPrev.clear();
  84.     const int COPY_DEPTH = 3;
  85.     //如果当前交易的 Merkle 分支深度小于 COPY_DEPTH,则需要从链上补充支持交易。
  86.     if (SetMerkleBranch() < COPY_DEPTH)
  87.     {
  88.         vector<uint256> vWorkQueue;
  89.         //遍历交易的所有输入,将每个输入的前置交易哈希加入工作队列 vWorkQueue。
  90.         foreach(const CTxIn& txin, vin)
  91.             vWorkQueue.push_back(txin.prevout.hash);
  92.         // This critsect is OK because txdb is already open
  93.         CRITICAL_BLOCK(cs_mapWallet)
  94.         {
  95.             map<uint256, const CMerkleTx*> mapWalletPrev; //跟踪处理过的交易。
  96.             set<uint256> setAlreadyDone;  //用于记录已经处理的交易哈希,防止重复处理。
  97.             for (int i = 0; i < vWorkQueue.size(); i++)
  98.             {
  99.                 uint256 hash = vWorkQueue[i];
  100.                 if (setAlreadyDone.count(hash))
  101.                     continue;
  102.                 setAlreadyDone.insert(hash);
  103.                 //查找 hash 对应的交易 tx
  104.                 CMerkleTx tx;
  105.                 if (mapWallet.count(hash))
  106.                 {
  107.                     //如果交易存在于 mapWallet 中,则直接使用该交易,并且将其前置交易加入 mapWalletPrev。
  108.                     tx = mapWallet[hash];
  109.                     foreach(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
  110.                         mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
  111.                 }
  112.                 //如果 mapWallet 中不存在,则检查 mapWalletPrev
  113.                 else if (mapWalletPrev.count(hash))
  114.                 {
  115.                     tx = *mapWalletPrev[hash];
  116.                 }
  117.                 //也不存在则尝试从磁盘中读取
  118.                 else if (!fClient && txdb.ReadDiskTx(hash, tx))
  119.                 {
  120.                     ;
  121.                 }
  122.                 else
  123.                 {
  124.                     printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
  125.                     continue;
  126.                 }
  127.                 //调用 SetMerkleBranch() 更新 tx 的 Merkle 分支深度。如果深度小于 COPY_DEPTH,则继续追溯前置交易,直到达到指定深度。
  128.                 int nDepth = tx.SetMerkleBranch();
  129.                 vtxPrev.push_back(tx);
  130.                 if (nDepth < COPY_DEPTH)
  131.                     foreach(const CTxIn& txin, tx.vin)
  132.                         vWorkQueue.push_back(txin.prevout.hash);
  133.             }
  134.         }
  135.     }
  136.     //反转 vtxPrev 中的交易顺序,以确保这些支持交易按照正确的顺序(从最新到最旧)排列。
  137.     reverse(vtxPrev.begin(), vtxPrev.end());
  138. }
复制代码
总结

以上是比特币在发送到网络之前,创建一个交易的根本流程,有错误的盼望指正。
回复

使用道具 举报

返回列表 发新帖
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录

QQ|手机版|qidao123.com IT社区;IT企服评测▪应用市场 ( 浙ICP备20004199|浙ICP备20004199号 )|网站地图

GMT+8, 2026-11-7 00:22 , Processed in 0.024468 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表